| | | 1 | | |
| | | 2 | | <# |
| | | 3 | | .SYNOPSIS |
| | | 4 | | Resolves a file path relative to the Kestrun root or a specified base path. |
| | | 5 | | .DESCRIPTION |
| | | 6 | | This function expands environment variables and resolves the provided path against the Kestrun root or a specifi |
| | | 7 | | If the path is relative, it combines it with the base path. If the -Test switch is used, it checks if the resolv |
| | | 8 | | .PARAMETER Path |
| | | 9 | | The path to resolve. This can be an absolute path or a relative path. |
| | | 10 | | .PARAMETER RelativeBasePath |
| | | 11 | | An optional base path to resolve the relative path against. If not specified, the current directory is used. |
| | | 12 | | .PARAMETER KestrunRoot |
| | | 13 | | If specified, the Kestrun root directory is used as the base path for resolving the relative path. |
| | | 14 | | .PARAMETER Test |
| | | 15 | | If specified, the function will check if the resolved path exists. If it does not, the original input path is re |
| | | 16 | | .EXAMPLE |
| | | 17 | | Resolve-KrPath -Path "~/Documents/file.txt" -KestrunRoot |
| | | 18 | | Resolves the path "~/Documents/file.txt" relative to the Kestrun root directory, expanding any environment varia |
| | | 19 | | .EXAMPLE |
| | | 20 | | Resolve-KrPath -Path "file.txt" -RelativeBasePath "C:\Base\Path" |
| | | 21 | | Resolves the path "file.txt" relative to "C:\Base\Path", expanding any environment variables. |
| | | 22 | | .NOTES |
| | | 23 | | This function is designed to be used in the context of a Kestrun server to resolve file paths correctly. |
| | | 24 | | #> |
| | | 25 | | function Resolve-KrPath { |
| | | 26 | | [KestrunRuntimeApi('Everywhere')] |
| | | 27 | | [CmdletBinding(DefaultParameterSetName = 'RelativeBasePath')] |
| | | 28 | | [OutputType([string])] |
| | | 29 | | param( |
| | | 30 | | [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline)] |
| | | 31 | | [string] $Path, |
| | | 32 | | |
| | | 33 | | [Parameter(parameterSetName = 'RelativeBasePath')] |
| | | 34 | | [string] $RelativeBasePath, |
| | | 35 | | |
| | | 36 | | [Parameter(parameterSetName = 'KestrunRoot')] |
| | | 37 | | [switch] $KestrunRoot, |
| | | 38 | | |
| | | 39 | | [Parameter()] |
| | | 40 | | [switch] $Test |
| | | 41 | | ) |
| | | 42 | | process { |
| | | 43 | | # --- 1. Expand ~/env in both Path and, if supplied, RelativeBasePath --- |
| | 1 | 44 | | $expand = { |
| | | 45 | | param($p) |
| | 1 | 46 | | if ($p -like '~*') { |
| | 0 | 47 | | $p = $p -replace '^~', $HOME |
| | | 48 | | } |
| | 1 | 49 | | [Environment]::ExpandEnvironmentVariables($p) |
| | | 50 | | } |
| | | 51 | | |
| | 1 | 52 | | $p3 = & $expand $Path |
| | | 53 | | |
| | 1 | 54 | | if ($KestrunRoot) { |
| | | 55 | | # Use the Kestrun root as base |
| | 1 | 56 | | $RelativeBasePath = [Kestrun.KestrunHostManager]::KestrunRoot |
| | | 57 | | } |
| | | 58 | | |
| | 1 | 59 | | if ($RelativeBasePath) { |
| | | 60 | | # Expand + normalize the base, even if it doesn't exist |
| | 1 | 61 | | $base3 = & $expand $RelativeBasePath |
| | 1 | 62 | | $baseFull = [IO.Path]::GetFullPath($base3) |
| | | 63 | | |
| | 1 | 64 | | if ([IO.Path]::IsPathRooted($p3)) { |
| | 0 | 65 | | $full = [IO.Path]::GetFullPath($p3) |
| | | 66 | | } else { |
| | | 67 | | # Combine and normalize WITHOUT requiring the target to exist |
| | 1 | 68 | | $combined = [IO.Path]::Combine($baseFull, $p3) |
| | 1 | 69 | | $full = [IO.Path]::GetFullPath($combined) |
| | | 70 | | } |
| | | 71 | | } else { |
| | | 72 | | # No base supplied: just make absolute against current directory |
| | 0 | 73 | | $full = [IO.Path]::GetFullPath($p3) |
| | | 74 | | } |
| | | 75 | | |
| | | 76 | | # --- 3. Normalize directory separators to the current platform & remove '\.' segments --- |
| | 1 | 77 | | if ([IO.Path]::DirectorySeparatorChar -eq '\\') { |
| | | 78 | | # Windows: favor backslashes |
| | 0 | 79 | | $full = $full -replace '/', '\\' |
| | | 80 | | } else { |
| | | 81 | | # *nix: favor forward slashes |
| | 1 | 82 | | $full = $full -replace '\\', '/' |
| | | 83 | | } |
| | | 84 | | # Remove any /./ or \./ style segments (keep UNC // at start intact) |
| | 1 | 85 | | $full = $full -replace '([\\/])\.(?=[\\/])', '$1' |
| | | 86 | | # Collapse any accidental duplicate separators except a leading UNC // |
| | 1 | 87 | | if ($full -notmatch '^[\\/]{2}[^\\/]') { |
| | 1 | 88 | | $full = $full -replace '([\\/]){2,}', '$1' |
| | | 89 | | } |
| | | 90 | | |
| | | 91 | | # --- 4. If -Test was used and file doesn't exist, return the original input Path --- |
| | 2 | 92 | | if ($Test -and -not (Test-Path $full)) { |
| | 1 | 93 | | return $Path |
| | | 94 | | } |
| | | 95 | | |
| | 1 | 96 | | return $full |
| | | 97 | | } |
| | | 98 | | } |
| | | 99 | | |