GitViz.psm1
# save directory script was imported from $web_dir = $PSScriptRoot function Show-GitViz { $git_dir = Get-Location $web_host = "http://localhost:6776/" Write-Host $git_dir Write-Host $web_dir Write-Host $web_host Start-Process -PSPath ($web_host + "") $routes = @{ "^/$" = { try { return Get-Content (Join-Path -Path $web_dir -ChildPath "graph.html") -raw } catch { return $_.Exception | Format-List -Force | Out-String } } "^/svg$" = { try { $command = Join-Path -Path $web_dir -ChildPath "graph.ps1" $dot = Invoke-Expression -Command $command $svg = $dot | dot.exe -Tsvg | Out-String $svg = $svg.Substring([math]::max(0, $svg.IndexOf("<svg"))) return $svg } catch { return $_.Exception | Format-List -Force | Out-String } } "^/dot$" = { try { $dot = (Invoke-Expression -Command (Join-Path -Path $web_dirr -ChildPath "graph.ps1")) return $dot } catch { return $_.Exception | Format-List -Force | Out-String } } "^/show/(.+)$" = { param([string[]]$args) try { return "<pre>$((git show $args) -join "`n")</pre>" } catch { return $_.Exception | Format-List -Force | Out-String } } "^/([^/]+\.(html|css|js))$" = { param([string[]]$args) try { return Get-Content (Join-Path -Path $web_dir -ChildPath $args[0]) -raw } catch { return $_.Exception | Format-List -Force | Out-String } } "^/watch$" = { param([string[]]$args) try { $watcher = New-Object System.IO.FileSystemWatcher $watcher.Path = (Join-Path -Path $git_dir -ChildPath ".git\logs") $watcher.IncludeSubdirectories = $true $watcher.EnableRaisingEvents = $false $watcher.NotifyFilter = [System.IO.NotifyFilters]::LastWrite -bor [System.IO.NotifyFilters]::FileName $results = @() $result = $watcher.WaitForChanged([System.IO.WatcherChangeTypes]::Changed -bor [System.IO.WatcherChangeTypes]::Renamed -bOr [System.IO.WatcherChangeTypes]::Created, 5000); $results += $result if ($result.TimedOut -eq $false) { # wait for 1 second of inactivity while ($true) { $result = $watcher.WaitForChanged([System.IO.WatcherChangeTypes]::Changed -bor [System.IO.WatcherChangeTypes]::Renamed -bOr [System.IO.WatcherChangeTypes]::Created, 1000); if ($result.TimedOut -eq $true) { break } else { $results += $result } } } return $results } catch { return $_.Exception | Format-List -Force | Out-String } } "^/kill$" = { return "" } } $listener = New-Object System.Net.HttpListener $listener.Prefixes.Add($web_host) $listener.Start() $RunspacePool = [RunspaceFactory ]::CreateRunspacePool(5, 10) $RunspacePool.Open() Write-Host "Listening at $web_host..." while ($listener.IsListening) { $context = $listener.GetContext() $request = $context.Request $response = $context.Response Write-Host "`n> $($request.Url.LocalPath)" $localPath = $request.Url.LocalPath if ($localPath -eq "/kill") { $response.Close() $listener.Close() continue } $matched = $false foreach ($route_entry in $routes.GetEnumerator()) { $match = [regex]::Match($localPath, $route_entry.Key) if ($match.Success) { $route = $route_entry.Value $params = $match.Captures.Groups | %{ $_.Value } Write-Host " matched $($route_entry.Key)" Write-Host " params $($params -join ", ")" break } } if (-not $match.Success) { $response.StatusCode = 404 $response.Close() } else { $request_script = { param($request, $response, $route, $params) try { $content = & $route @params if (-not ($content -is [string])) { $content = ($content | ConvertTo-Json) $response.ContentType = "application/json" } } catch { $content = $_.Exception | Format-List -Force | Out-String } $buffer = [System.Text.Encoding]::UTF8.GetBytes($content) $response.ContentLength64 = $buffer.Length $response.OutputStream.Write($buffer, 0, $buffer.Length) $response.Close() } $request_task = [powershell]::Create(). AddScript($request_script). AddArgument($request). AddArgument($response). AddArgument($route). AddArgument($params) $request_task.RunspacePool = $RunspacePool $task_result = $request_task.BeginInvoke() } Start-Sleep -Milliseconds 50 } $RunspacePool.Close() } Export-ModuleMember -Function Show-GitViz |