mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-17 12:45:47 +00:00
Fix PATH caching in CommandDiscovery code (#27809)
The method `GetLookupDirectoryPaths` always returns the cached instance of path collection. However, the returned collection gets mutated in `CommandPathSearch.ResolveCurrentDirectoryInLookupPaths` to resolve the relative paths such as `.\tools` based on the user's current working directory `$PWD`, so for example, `.\tools` gets replaced with `cwd-1\tools` in the cached instance. Then, when the user changes to a different working directory `cwd-2`, command discovery won't find the executable or ps1 script under `cwd-2/tools` as expected, but those executables under `cwd-1\tools` will always be discoverable no matter what the `$PWD` is. That behavior is incorrect. This pull request improves the caching logic of `GetLookupDirectoryPaths` and makes it return a copy of the path collection, so the mutation happens to the returned copy, and the cached instance is kept intact. So, for every command search, the `CommandPathSearch` will resolve relative paths against the `$PWD` that the user is located at that time.
This commit is contained in:
1 parent
f83ccddf80
commit
bac40c877b
2 files changed
+84
-46
No files matched your search
@@ -275,3 +275,54 @@ Describe "Get-Command Tests" -Tags "CI" {
|
||||
$result | Should -Be $null
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Test relative path in PATH env var" -Tags "CI" {
|
||||
|
||||
BeforeAll {
|
||||
$originalPath = $env:PATH
|
||||
$originalLocation = Get-Location
|
||||
|
||||
$subDir1 = Join-Path $TestDrive -ChildPath "subdir1"
|
||||
$subDir2 = Join-Path $TestDrive -ChildPath "subdir2"
|
||||
$toolsUnderSubDir1 = Join-Path $subDir1 -ChildPath "tools"
|
||||
$toolsUnderSubDir2 = Join-Path $subDir2 -ChildPath "tools"
|
||||
|
||||
$null = New-Item -Path $subDir1 -ItemType Directory -Force
|
||||
$null = New-Item -Path $subDir2 -ItemType Directory -Force
|
||||
$null = New-Item -Path $toolsUnderSubDir1 -ItemType Directory -Force
|
||||
$null = New-Item -Path $toolsUnderSubDir2 -ItemType Directory -Force
|
||||
|
||||
$helloScript = Join-Path $toolsUnderSubDir1 -ChildPath "hello.ps1"
|
||||
$byeScript = Join-Path $toolsUnderSubDir2 -ChildPath "bye.ps1"
|
||||
$null = New-Item -Path $helloScript -ItemType File -Force
|
||||
$null = New-Item -Path $byeScript -ItemType File -Force
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
Set-Location $originalLocation
|
||||
$env:PATH = $originalPath
|
||||
}
|
||||
|
||||
It "Get-Command should resolve relative path in PATH env var based on user's current working directory" {
|
||||
$dirSep = [System.IO.Path]::DirectorySeparatorChar
|
||||
$pathSep = [System.IO.Path]::PathSeparator
|
||||
|
||||
Set-Location $subDir1
|
||||
$env:PATH = ".${dirSep}tools${pathSep}$env:PATH"
|
||||
|
||||
$result = Get-Command "hello.ps1" -ErrorAction silentlycontinue
|
||||
$result | Should -Not -BeNullOrEmpty -Because "CWD is $subDir1, so '.${dirSep}tools' in PATH should be resolved to '$toolsUnderSubDir1', which contains 'hello.ps1'"
|
||||
$result.Path | Should -BeExactly $helloScript
|
||||
|
||||
$result = Get-Command "bye.ps1" -ErrorAction silentlycontinue
|
||||
$result | Should -BeNullOrEmpty -Because "'bye.ps1' is not in '$toolsUnderSubDir1'"
|
||||
|
||||
Set-Location $subDir2
|
||||
$result = Get-Command "hello.ps1" -ErrorAction silentlycontinue
|
||||
$result | Should -BeNullOrEmpty -Because "CWD is $subDir2, so '.${dirSep}tools' in PATH should be resolved to '$toolsUnderSubDir2', which contains 'bye.ps1'"
|
||||
|
||||
$result = Get-Command "bye.ps1" -ErrorAction silentlycontinue
|
||||
$result | Should -Not -BeNullOrEmpty
|
||||
$result.Path | Should -BeExactly $byeScript
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user