mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-13 21:32:06 +00:00
Honor -Recurse when Get-ChildItem uses -Name (#28078)
This commit is contained in:
1 parent
373f6a7b79
commit
5d871eb5e0
2 files changed
+160
-46
No files matched your search
@@ -1323,52 +1323,7 @@ namespace System.Management.Automation
|
||||
|
||||
try
|
||||
{
|
||||
// If we're recursing, do some path fixups to match user
|
||||
// expectations, but only if the last part is a file and not a directory:
|
||||
if (recurse && !path.EndsWith(Path.DirectorySeparatorChar) && !path.EndsWith(Path.AltDirectorySeparatorChar))
|
||||
{
|
||||
string childName = GetChildName(path, context);
|
||||
|
||||
// If -File or -Directory is specified and path is ended with '*', we should include the parent path as search path
|
||||
|
||||
bool isFileOrDirectoryPresent = false;
|
||||
|
||||
if (context.DynamicParameters is Microsoft.PowerShell.Commands.GetChildDynamicParameters dynParam)
|
||||
{
|
||||
isFileOrDirectoryPresent = dynParam.File.IsPresent || dynParam.Directory.IsPresent;
|
||||
}
|
||||
|
||||
if (string.Equals(childName, "*", StringComparison.OrdinalIgnoreCase) && isFileOrDirectoryPresent)
|
||||
{
|
||||
string parentName = path.Substring(0, path.Length - childName.Length);
|
||||
path = parentName;
|
||||
}
|
||||
// dir c:\tem* -include *.ps1 -rec => No change
|
||||
if ((context.Include == null) || (context.Include.Count == 0))
|
||||
{
|
||||
// dir c:\tem* -rec => dir c:\ -include tem* -rec
|
||||
// dir tem* -rec => dir -include tem* -rec
|
||||
// dir temp -rec
|
||||
|
||||
// Should glob paths and files that match tem*, but then
|
||||
// recurse into all subdirectories and do the same for
|
||||
// those directories.
|
||||
if (!string.IsNullOrEmpty(path) && !IsItemContainer(path))
|
||||
{
|
||||
if (!string.Equals(childName, "*", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (context.Include != null)
|
||||
{
|
||||
context.Include.Add(childName);
|
||||
modifiedInclude = true;
|
||||
}
|
||||
}
|
||||
|
||||
string parentName = path.Substring(0, path.Length - childName.Length);
|
||||
path = parentName;
|
||||
}
|
||||
}
|
||||
}
|
||||
modifiedInclude = NormalizePathForChildItemRecursion(ref path, recurse, context);
|
||||
|
||||
// Save the include and exclude filters so that we can ignore
|
||||
// them when doing recursion
|
||||
@@ -1529,6 +1484,63 @@ namespace System.Management.Automation
|
||||
}
|
||||
}
|
||||
|
||||
private bool NormalizePathForChildItemRecursion(
|
||||
ref string path,
|
||||
bool recurse,
|
||||
CmdletProviderContext context)
|
||||
{
|
||||
bool modifiedInclude = false;
|
||||
|
||||
// If we're recursing, do some path fixups to match user
|
||||
// expectations, but only if the last part is a file and not a directory:
|
||||
if (recurse && !path.EndsWith(Path.DirectorySeparatorChar) && !path.EndsWith(Path.AltDirectorySeparatorChar))
|
||||
{
|
||||
string childName = GetChildName(path, context);
|
||||
|
||||
// If -File or -Directory is specified and path is ended with '*', we should include the parent path as search path
|
||||
|
||||
bool isFileOrDirectoryPresent = false;
|
||||
|
||||
if (context.DynamicParameters is Microsoft.PowerShell.Commands.GetChildDynamicParameters dynParam)
|
||||
{
|
||||
isFileOrDirectoryPresent = dynParam.File.IsPresent || dynParam.Directory.IsPresent;
|
||||
}
|
||||
|
||||
if (string.Equals(childName, "*", StringComparison.OrdinalIgnoreCase) && isFileOrDirectoryPresent)
|
||||
{
|
||||
string parentName = path.Substring(0, path.Length - childName.Length);
|
||||
path = parentName;
|
||||
}
|
||||
// dir c:\tem* -include *.ps1 -rec => No change
|
||||
if ((context.Include == null) || (context.Include.Count == 0))
|
||||
{
|
||||
// dir c:\tem* -rec => dir c:\ -include tem* -rec
|
||||
// dir tem* -rec => dir -include tem* -rec
|
||||
// dir temp -rec
|
||||
|
||||
// Should glob paths and files that match tem*, but then
|
||||
// recurse into all subdirectories and do the same for
|
||||
// those directories.
|
||||
if (!string.IsNullOrEmpty(path) && !IsItemContainer(path))
|
||||
{
|
||||
if (!string.Equals(childName, "*", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (context.Include != null)
|
||||
{
|
||||
context.Include.Add(childName);
|
||||
modifiedInclude = true;
|
||||
}
|
||||
}
|
||||
|
||||
string parentName = path.Substring(0, path.Length - childName.Length);
|
||||
path = parentName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modifiedInclude;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child items of the item at the specified path.
|
||||
/// </summary>
|
||||
@@ -2229,6 +2241,10 @@ namespace System.Management.Automation
|
||||
}
|
||||
|
||||
CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);
|
||||
context.SetFilters(
|
||||
include: new Collection<string>(),
|
||||
exclude: new Collection<string>(),
|
||||
filter: null);
|
||||
context.Force = force;
|
||||
context.SuppressWildcardExpansion = literalPath;
|
||||
|
||||
@@ -2319,6 +2335,33 @@ namespace System.Management.Automation
|
||||
throw PSTraceSource.NewArgumentNullException(nameof(path));
|
||||
}
|
||||
|
||||
bool modifiedInclude = false;
|
||||
|
||||
try
|
||||
{
|
||||
if ((recurse && !context.SuppressWildcardExpansion) || LocationGlobber.ShouldPerformGlobbing(path, context))
|
||||
{
|
||||
modifiedInclude = NormalizePathForChildItemRecursion(ref path, recurse, context);
|
||||
}
|
||||
|
||||
GetChildNamesCore(path, returnContainers, recurse, depth, context);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (modifiedInclude)
|
||||
{
|
||||
context.Include.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetChildNamesCore(
|
||||
string path,
|
||||
ReturnContainers returnContainers,
|
||||
bool recurse,
|
||||
uint depth,
|
||||
CmdletProviderContext context)
|
||||
{
|
||||
// Construct the include filter
|
||||
|
||||
Collection<WildcardPattern> includeMatcher =
|
||||
|
||||
@@ -142,6 +142,77 @@ Describe "Get-ChildItem" -Tags "CI" {
|
||||
(Get-ChildItem -Path $TestDrive -Depth 1 -Exclude $item_a).Count | Should -Be 7
|
||||
}
|
||||
|
||||
It "Should return names recursively when the path has a wildcard leaf" {
|
||||
$root = New-Item -Path $TestDrive -Name "NameRecurse" -ItemType Directory
|
||||
try {
|
||||
$child = New-Item -Path $root -Name "Child" -ItemType Directory
|
||||
$null = New-Item -Path $root -Name "root.md" -ItemType File
|
||||
$null = New-Item -Path $child -Name "child.md" -ItemType File
|
||||
$null = New-Item -Path $child -Name "ignored.txt" -ItemType File
|
||||
$path = Join-Path $root "*.md"
|
||||
|
||||
$result = Get-ChildItem -Path $path -Recurse -File -Name
|
||||
$result | Should -HaveCount 2
|
||||
$result | Should -Contain "root.md"
|
||||
$result | Should -Contain "Child$([IO.Path]::DirectorySeparatorChar)child.md"
|
||||
|
||||
Get-ChildItem -Path $path -Depth 0 -File -Name | Should -BeExactly "root.md"
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $root -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
It "Should preserve recursive wildcard filters through the public GetNames API" {
|
||||
$root = New-Item -Path $TestDrive -Name "PublicGetNamesRecurse" -ItemType Directory
|
||||
try {
|
||||
$child = New-Item -Path $root -Name "Child" -ItemType Directory
|
||||
$null = New-Item -Path $root -Name "root.md" -ItemType File
|
||||
$null = New-Item -Path $child -Name "child.md" -ItemType File
|
||||
$null = New-Item -Path $child -Name "ignored.txt" -ItemType File
|
||||
$path = Join-Path $root "*.md"
|
||||
|
||||
$result = $ExecutionContext.SessionState.InvokeProvider.ChildItem.GetNames(
|
||||
$path,
|
||||
[System.Management.Automation.ReturnContainers]::ReturnMatchingContainers,
|
||||
$true)
|
||||
|
||||
$result | Should -HaveCount 2
|
||||
$result | Should -Contain "root.md"
|
||||
$result | Should -Contain "Child$([IO.Path]::DirectorySeparatorChar)child.md"
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $root -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
It "Should resolve recursive leaf paths from the current directory" {
|
||||
$root = New-Item -Path $TestDrive -Name "CurrentDirectoryRecurse" -ItemType Directory
|
||||
try {
|
||||
$child = New-Item -Path $root -Name "Child" -ItemType Directory
|
||||
$rootFile = New-Item -Path $root -Name "root.md" -ItemType File
|
||||
$childFile = New-Item -Path $child -Name "child.md" -ItemType File
|
||||
|
||||
Push-Location $root
|
||||
try {
|
||||
$result = Get-ChildItem *.md -Recurse -File -Name
|
||||
$result | Should -HaveCount 2
|
||||
$result | Should -Contain $rootFile.Name
|
||||
$result | Should -Contain "Child$([IO.Path]::DirectorySeparatorChar)$($childFile.Name)"
|
||||
|
||||
$result = Get-ChildItem child.md -Recurse -File -Name
|
||||
$result | Should -HaveCount 1
|
||||
$result | Should -BeExactly "Child$([IO.Path]::DirectorySeparatorChar)$($childFile.Name)"
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $root -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
It "Should return items recursively when using 'Include' or 'Exclude' parameters with -LiteralPath" {
|
||||
(Get-ChildItem -LiteralPath $TestDrive -Recurse -Exclude *).Count | Should -Be 0
|
||||
(Get-ChildItem -LiteralPath $TestDrive -Recurse -Include *.dll).Count | Should -Be (Get-ChildItem $TestDrive -Recurse -Include *.dll).Count
|
||||
|
||||
Reference in new issue
Block a user