correct Unhandled exception. System.IO.FileNotFoundException: Could not find file '/opt/jellyfin/ServerSetupApp/index.mstemplate.html'.
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
# Async Migration Analysis Script
|
||||
# Scans the Jellyfin codebase for synchronous database operations that need conversion
|
||||
|
||||
param(
|
||||
[string]$Path = ".",
|
||||
[switch]$DetailedReport,
|
||||
[switch]$ExportCsv
|
||||
)
|
||||
|
||||
Write-Host "🔍 Scanning for synchronous database operations..." -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Define patterns to search for
|
||||
$patterns = @{
|
||||
"SaveChanges" = @{
|
||||
Pattern = "\.SaveChanges\s*\(\s*\)"
|
||||
Replacement = "await .SaveChangesAsync(cancellationToken)"
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous database save operation"
|
||||
}
|
||||
"ToList" = @{
|
||||
Pattern = "\.ToList\s*\(\s*\)"
|
||||
Replacement = "await .ToListAsync(cancellationToken)"
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous list materialization"
|
||||
}
|
||||
"ToArray" = @{
|
||||
Pattern = "\.ToArray\s*\(\s*\)"
|
||||
Replacement = "await .ToArrayAsync(cancellationToken)"
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous array materialization"
|
||||
}
|
||||
"FirstOrDefault" = @{
|
||||
Pattern = "\.FirstOrDefault\s*\("
|
||||
Replacement = 'await .FirstOrDefaultAsync('
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous first element query"
|
||||
}
|
||||
"First" = @{
|
||||
Pattern = "\.First\s*\("
|
||||
Replacement = 'await .FirstAsync('
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous first element query"
|
||||
}
|
||||
"SingleOrDefault" = @{
|
||||
Pattern = "\.SingleOrDefault\s*\("
|
||||
Replacement = 'await .SingleOrDefaultAsync('
|
||||
Severity = "MEDIUM"
|
||||
Description = "Synchronous single element query"
|
||||
}
|
||||
"Single" = @{
|
||||
Pattern = "\.Single\s*\("
|
||||
Replacement = 'await .SingleAsync('
|
||||
Severity = "MEDIUM"
|
||||
Description = "Synchronous single element query"
|
||||
}
|
||||
"Any" = @{
|
||||
Pattern = "\.Any\s*\("
|
||||
Replacement = 'await .AnyAsync('
|
||||
Severity = "MEDIUM"
|
||||
Description = "Synchronous existence check"
|
||||
}
|
||||
"Count" = @{
|
||||
Pattern = "\.Count\s*\(\s*\)"
|
||||
Replacement = "await .CountAsync(cancellationToken)"
|
||||
Severity = "MEDIUM"
|
||||
Description = "Synchronous count operation"
|
||||
}
|
||||
"LongCount" = @{
|
||||
Pattern = "\.LongCount\s*\("
|
||||
Replacement = "await .LongCountAsync("
|
||||
Severity = "MEDIUM"
|
||||
Description = "Synchronous long count operation"
|
||||
}
|
||||
"ExecuteDelete" = @{
|
||||
Pattern = "\.ExecuteDelete\s*\(\s*\)"
|
||||
Replacement = "await .ExecuteDeleteAsync(cancellationToken)"
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous bulk delete"
|
||||
}
|
||||
"ExecuteUpdate" = @{
|
||||
Pattern = "\.ExecuteUpdate\s*\("
|
||||
Replacement = "await .ExecuteUpdateAsync("
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous bulk update"
|
||||
}
|
||||
"BeginTransaction" = @{
|
||||
Pattern = "\.BeginTransaction\s*\(\s*\)"
|
||||
Replacement = "await .BeginTransactionAsync(cancellationToken)"
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous transaction start"
|
||||
}
|
||||
"Commit" = @{
|
||||
Pattern = "transaction\.Commit\s*\(\s*\)"
|
||||
Replacement = "await transaction.CommitAsync(cancellationToken)"
|
||||
Severity = "HIGH"
|
||||
Description = "Synchronous transaction commit"
|
||||
}
|
||||
"Rollback" = @{
|
||||
Pattern = "transaction\.Rollback\s*\(\s*\)"
|
||||
Replacement = "await transaction.RollbackAsync(cancellationToken)"
|
||||
Severity = "MEDIUM"
|
||||
Description = "Synchronous transaction rollback"
|
||||
}
|
||||
"Sum" = @{
|
||||
Pattern = "\.Sum\s*\("
|
||||
Replacement = 'await .SumAsync('
|
||||
Severity = "LOW"
|
||||
Description = "Synchronous sum aggregation"
|
||||
}
|
||||
"Average" = @{
|
||||
Pattern = "\.Average\s*\("
|
||||
Replacement = 'await .AverageAsync('
|
||||
Severity = "LOW"
|
||||
Description = "Synchronous average aggregation"
|
||||
}
|
||||
"Min" = @{
|
||||
Pattern = "\.Min\s*\("
|
||||
Replacement = 'await .MinAsync('
|
||||
Severity = "LOW"
|
||||
Description = "Synchronous min aggregation"
|
||||
}
|
||||
"Max" = @{
|
||||
Pattern = "\.Max\s*\("
|
||||
Replacement = 'await .MaxAsync('
|
||||
Severity = "LOW"
|
||||
Description = "Synchronous max aggregation"
|
||||
}
|
||||
"Load" = @{
|
||||
Pattern = "\.Load\s*\(\s*\)"
|
||||
Replacement = 'await .LoadAsync(cancellationToken)'
|
||||
Severity = "MEDIUM"
|
||||
Description = "Synchronous navigation property load"
|
||||
}
|
||||
}
|
||||
|
||||
# Exclude patterns (already async or intentionally sync)
|
||||
$excludePatterns = @(
|
||||
"Async\s*\(",
|
||||
"// ASYNC",
|
||||
"\.ConfigureAwait",
|
||||
"AsyncEnumerable"
|
||||
)
|
||||
|
||||
# Get all .cs files, excluding test files and migrations initially
|
||||
$files = Get-ChildItem -Path $Path -Recurse -Filter "*.cs" |
|
||||
Where-Object {
|
||||
$_.FullName -notmatch "\\bin\\" -and
|
||||
$_.FullName -notmatch "\\obj\\" -and
|
||||
$_.FullName -notmatch "\\Migrations\\" -and
|
||||
$_.FullName -notmatch "\.Designer\.cs$"
|
||||
}
|
||||
|
||||
$results = @()
|
||||
$summary = @{}
|
||||
|
||||
foreach ($file in $files) {
|
||||
$content = Get-Content -Path $file.FullName -Raw
|
||||
|
||||
foreach ($patternName in $patterns.Keys) {
|
||||
$patternInfo = $patterns[$patternName]
|
||||
$pattern = $patternInfo.Pattern
|
||||
|
||||
# Find matches
|
||||
$matches = [regex]::Matches($content, $pattern)
|
||||
|
||||
foreach ($match in $matches) {
|
||||
# Check if this line is already async or should be excluded
|
||||
$lineStart = $content.Substring(0, $match.Index).LastIndexOf("`n")
|
||||
if ($lineStart -lt 0) { $lineStart = 0 }
|
||||
$lineEnd = $content.IndexOf("`n", $match.Index)
|
||||
if ($lineEnd -lt 0) { $lineEnd = $content.Length }
|
||||
|
||||
$line = $content.Substring($lineStart, $lineEnd - $lineStart).Trim()
|
||||
|
||||
# Skip if already async or excluded
|
||||
$shouldExclude = $false
|
||||
foreach ($excludePattern in $excludePatterns) {
|
||||
if ($line -match $excludePattern) {
|
||||
$shouldExclude = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $shouldExclude) {
|
||||
# Calculate line number
|
||||
$lineNumber = ($content.Substring(0, $match.Index) -split "`n").Count
|
||||
|
||||
$result = [PSCustomObject]@{
|
||||
File = $file.FullName.Replace($Path, "").TrimStart('\')
|
||||
LineNumber = $lineNumber
|
||||
Pattern = $patternName
|
||||
Severity = $patternInfo.Severity
|
||||
Description = $patternInfo.Description
|
||||
MatchedText = $match.Value
|
||||
Line = $line
|
||||
Replacement = $patternInfo.Replacement
|
||||
}
|
||||
|
||||
$results += $result
|
||||
|
||||
# Update summary
|
||||
if (-not $summary.ContainsKey($patternName)) {
|
||||
$summary[$patternName] = 0
|
||||
}
|
||||
$summary[$patternName]++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Display results
|
||||
Write-Host "📊 Analysis Complete!" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "=" * 80 -ForegroundColor DarkGray
|
||||
Write-Host "SUMMARY" -ForegroundColor Yellow
|
||||
Write-Host "=" * 80 -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
$totalIssues = $results.Count
|
||||
$highSeverity = ($results | Where-Object { $_.Severity -eq "HIGH" }).Count
|
||||
$mediumSeverity = ($results | Where-Object { $_.Severity -eq "MEDIUM" }).Count
|
||||
$lowSeverity = ($results | Where-Object { $_.Severity -eq "LOW" }).Count
|
||||
|
||||
Write-Host "Total synchronous operations found: " -NoNewline
|
||||
Write-Host $totalIssues -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host " 🔴 HIGH severity: " -NoNewline
|
||||
Write-Host $highSeverity -ForegroundColor Red
|
||||
Write-Host " 🟡 MEDIUM severity: " -NoNewline
|
||||
Write-Host $mediumSeverity -ForegroundColor Yellow
|
||||
Write-Host " 🟢 LOW severity: " -NoNewline
|
||||
Write-Host $lowSeverity -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Breakdown by operation type:" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
$summary.GetEnumerator() | Sort-Object Value -Descending | ForEach-Object {
|
||||
$severity = $patterns[$_.Key].Severity
|
||||
$color = switch ($severity) {
|
||||
"HIGH" { "Red" }
|
||||
"MEDIUM" { "Yellow" }
|
||||
"LOW" { "Green" }
|
||||
}
|
||||
Write-Host " $($_.Key): " -NoNewline
|
||||
Write-Host $_.Value -ForegroundColor $color -NoNewline
|
||||
Write-Host " ($severity)"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=" * 80 -ForegroundColor DarkGray
|
||||
|
||||
if ($DetailedReport) {
|
||||
Write-Host ""
|
||||
Write-Host "DETAILED FINDINGS" -ForegroundColor Yellow
|
||||
Write-Host "=" * 80 -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
# Group by file
|
||||
$resultsByFile = $results | Group-Object -Property File
|
||||
|
||||
foreach ($fileGroup in $resultsByFile | Sort-Object Name) {
|
||||
Write-Host ""
|
||||
Write-Host "📄 $($fileGroup.Name)" -ForegroundColor Cyan
|
||||
Write-Host "-" * 80 -ForegroundColor DarkGray
|
||||
|
||||
foreach ($item in $fileGroup.Group | Sort-Object LineNumber) {
|
||||
$severityColor = switch ($item.Severity) {
|
||||
"HIGH" { "Red" }
|
||||
"MEDIUM" { "Yellow" }
|
||||
"LOW" { "Green" }
|
||||
}
|
||||
|
||||
Write-Host " Line $($item.LineNumber): " -NoNewline
|
||||
Write-Host "$($item.Pattern) " -NoNewline -ForegroundColor $severityColor
|
||||
Write-Host "- $($item.Description)"
|
||||
Write-Host " Current: " -NoNewline
|
||||
Write-Host $item.MatchedText -ForegroundColor Gray
|
||||
Write-Host " Replacement: " -NoNewline
|
||||
Write-Host $item.Replacement -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($ExportCsv) {
|
||||
$csvPath = Join-Path $Path "async_migration_report.csv"
|
||||
$results | Export-Csv -Path $csvPath -NoTypeInformation
|
||||
Write-Host ""
|
||||
Write-Host "📁 Report exported to: " -NoNewline
|
||||
Write-Host $csvPath -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "💡 TIP: Run with -DetailedReport for line-by-line analysis" -ForegroundColor DarkGray
|
||||
Write-Host "💡 TIP: Run with -ExportCsv to export findings to CSV" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
# Return results for further processing
|
||||
return $results
|
||||
Reference in New Issue
Block a user