Change how relative paths in Resolve-Path are handled when using the RelativeBasePath parameter (#19755)

This commit is contained in:
MartinGC94
2023-07-24 09:47:24 -07:00
committed by GitHub
parent 3b9e70cfc8
commit 3f128d680f
2 changed files with 123 additions and 51 deletions
@@ -22,8 +22,6 @@ namespace Microsoft.PowerShell.Commands
/// </summary>
[Parameter(Position = 0, ParameterSetName = "Path",
Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
[Parameter(Position = 0, ParameterSetName = "PathWithRelativeBase",
Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
public string[] Path
{
get
@@ -42,8 +40,6 @@ namespace Microsoft.PowerShell.Commands
/// </summary>
[Parameter(ParameterSetName = "LiteralPath",
Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]
[Parameter(ParameterSetName = "LiteralPathWithRelativeBase",
Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]
[Alias("PSPath", "LP")]
public string[] LiteralPath
{
@@ -83,8 +79,7 @@ namespace Microsoft.PowerShell.Commands
/// <summary>
/// Gets or sets the path the resolved relative path should be based off.
/// </summary>
[Parameter(Mandatory = true, ParameterSetName = "PathWithRelativeBase")]
[Parameter(Mandatory = true, ParameterSetName = "LiteralPathWithRelativeBase")]
[Parameter]
public string RelativeBasePath
{
get
@@ -94,7 +89,6 @@ namespace Microsoft.PowerShell.Commands
set
{
_relative = true;
_relativeBasePath = value;
}
}
@@ -121,52 +115,50 @@ namespace Microsoft.PowerShell.Commands
/// </summary>
protected override void BeginProcessing()
{
if (_relative)
if (!string.IsNullOrEmpty(RelativeBasePath))
{
if (!string.IsNullOrEmpty(RelativeBasePath))
try
{
try
{
_relativeBasePath = SessionState.Internal.Globber.GetProviderPath(RelativeBasePath, CmdletProviderContext, out _, out _relativeDrive);
}
catch (ProviderNotFoundException providerNotFound)
{
ThrowTerminatingError(
new ErrorRecord(
providerNotFound.ErrorRecord,
providerNotFound));
}
catch (DriveNotFoundException driveNotFound)
{
ThrowTerminatingError(
new ErrorRecord(
driveNotFound.ErrorRecord,
driveNotFound));
}
catch (ProviderInvocationException providerInvocation)
{
ThrowTerminatingError(
new ErrorRecord(
providerInvocation.ErrorRecord,
providerInvocation));
}
catch (NotSupportedException notSupported)
{
ThrowTerminatingError(
new ErrorRecord(notSupported, "ProviderIsNotNavigationCmdletProvider", ErrorCategory.InvalidArgument, RelativeBasePath));
}
catch (InvalidOperationException invalidOperation)
{
ThrowTerminatingError(
new ErrorRecord(invalidOperation, "InvalidHomeLocation", ErrorCategory.InvalidOperation, RelativeBasePath));
}
return;
_relativeBasePath = SessionState.Internal.Globber.GetProviderPath(RelativeBasePath, CmdletProviderContext, out _, out _relativeDrive);
}
catch (ProviderNotFoundException providerNotFound)
{
ThrowTerminatingError(
new ErrorRecord(
providerNotFound.ErrorRecord,
providerNotFound));
}
catch (DriveNotFoundException driveNotFound)
{
ThrowTerminatingError(
new ErrorRecord(
driveNotFound.ErrorRecord,
driveNotFound));
}
catch (ProviderInvocationException providerInvocation)
{
ThrowTerminatingError(
new ErrorRecord(
providerInvocation.ErrorRecord,
providerInvocation));
}
catch (NotSupportedException notSupported)
{
ThrowTerminatingError(
new ErrorRecord(notSupported, "ProviderIsNotNavigationCmdletProvider", ErrorCategory.InvalidArgument, RelativeBasePath));
}
catch (InvalidOperationException invalidOperation)
{
ThrowTerminatingError(
new ErrorRecord(invalidOperation, "InvalidHomeLocation", ErrorCategory.InvalidOperation, RelativeBasePath));
}
return;
}
else if (_relative)
{
_relativeDrive = SessionState.Path.CurrentLocation.Drive;
_relativeBasePath = SessionState.Path.CurrentLocation.ProviderPath;
return;
}
}
@@ -181,7 +173,25 @@ namespace Microsoft.PowerShell.Commands
Collection<PathInfo> result = null;
try
{
result = SessionState.Path.GetResolvedPSPathFromPSPath(path, CmdletProviderContext);
if (MyInvocation.BoundParameters.ContainsKey("RelativeBasePath"))
{
// Pushing and popping the location is done because GetResolvedPSPathFromPSPath uses the current path to resolve relative paths.
// It's important that we pop the location before writing an object to the pipeline to avoid affecting downstream commands.
try
{
SessionState.Path.PushCurrentLocation(string.Empty);
_ = SessionState.Path.SetLocation(_relativeBasePath);
result = SessionState.Path.GetResolvedPSPathFromPSPath(path, CmdletProviderContext);
}
finally
{
_ = SessionState.Path.PopLocation(string.Empty);
}
}
else
{
result = SessionState.Path.GetResolvedPSPathFromPSPath(path, CmdletProviderContext);
}
if (_relative)
{
@@ -48,8 +48,70 @@ Describe "Resolve-Path returns proper path" -Tag "CI" {
Pop-Location
}
}
It 'Resolve-Path should support user specified base paths' {
$Expected = Join-Path -Path .\ -ChildPath fakeroot
Resolve-Path -Path $fakeRoot -RelativeBasePath $testRoot | Should -BeExactly $Expected
It 'Resolve-Path RelativeBasePath should handle <Scenario>' -TestCases @(
@{
Scenario = "Absolute Path, Absolute ReleativeBasePath"
Path = $root
Basepath = $testRoot
Expected = $root, ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot"
CD = $null
}
@{
Scenario = "Relative Path, Absolute ReleativeBasePath"
Path = ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot"
Basepath = $testRoot
Expected = $root, ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot"
CD = $null
}
@{
Scenario = "Relative Path, Relative ReleativeBasePath"
Path = ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot"
Basepath = ".$([System.IO.Path]::DirectorySeparatorChar)"
Expected = $root, ".$([System.IO.Path]::DirectorySeparatorChar)fakeroot"
CD = $testRoot
}
@{
Scenario = "Invalid Path, Absolute ReleativeBasePath"
Path = Join-Path $testRoot ThisPathDoesNotExist
Basepath = $root
Expected = $null
CD = $null
}
@{
Scenario = "Invalid Path, Invalid ReleativeBasePath"
Path = Join-Path $testRoot ThisPathDoesNotExist
Basepath = Join-Path $testRoot ThisPathDoesNotExist
Expected = $null
CD = $null
}
) -Test {
param($Path, $BasePath, $Expected, $CD)
if ($null -eq $Expected)
{
{Resolve-Path -Path $Path -RelativeBasePath $BasePath -ErrorAction Stop} | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.ResolvePathCommand"
{Resolve-Path -Path $Path -RelativeBasePath $BasePath -ErrorAction Stop -Relative} | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.ResolvePathCommand"
}
else
{
try
{
$OldLocation = if ($null -ne $CD)
{
$PWD
Set-Location $CD
}
(Resolve-Path -Path $Path -RelativeBasePath $BasePath).ProviderPath | Should -BeExactly $Expected[0]
Resolve-Path -Path $Path -RelativeBasePath $BasePath -Relative | Should -BeExactly $Expected[1]
}
finally
{
if ($null -ne $OldLocation)
{
Set-Location $OldLocation
}
}
}
}
}