Enable discovering modules that have names same as a culture (e.g. Az) (#8777)
Here are the major changes: - Add logic to skip checking for possible resource directories for the first set of sub directories from the top level. - There was an additional skip if the folder is hidden, rather than doing an explicit attribute check, change the `EnumerationOption` to skip hidden folders. - Since the `IsPossibleModuleDirectory()` helper now only checks to see if the name matches a culture, renamed to `IsPossibleResourceDirectory()` - When getting the default modules, we don't search recursively into individual module folders, so removed additional check for possible resource directory.
This commit is contained in:
parent
4de3a72142
commit
b06ad6aa61
|
@ -16,35 +16,34 @@ namespace System.Management.Automation.Internal
|
|||
// - Ignore files/directories when access is denied;
|
||||
// - Search top directory only.
|
||||
private static readonly System.IO.EnumerationOptions s_defaultEnumerationOptions =
|
||||
new System.IO.EnumerationOptions() { AttributesToSkip = 0 };
|
||||
new System.IO.EnumerationOptions() { AttributesToSkip = FileAttributes.Hidden };
|
||||
|
||||
// Default option for UNC path enumeration. Same as above plus a large buffer size.
|
||||
// For network shares, a large buffer may result in better performance as more results can be batched over the wire.
|
||||
// The buffer size 16K is recommended in the comment of the 'BufferSize' property:
|
||||
// "A "large" buffer, for example, would be 16K. Typical is 4K."
|
||||
private static readonly System.IO.EnumerationOptions s_uncPathEnumerationOptions =
|
||||
new System.IO.EnumerationOptions() { AttributesToSkip = 0, BufferSize = 16384 };
|
||||
new System.IO.EnumerationOptions() { AttributesToSkip = FileAttributes.Hidden, BufferSize = 16384 };
|
||||
|
||||
private static readonly string EnCulturePath = Path.DirectorySeparatorChar + "en";
|
||||
private static readonly string EnUsCulturePath = Path.DirectorySeparatorChar + "en-us";
|
||||
|
||||
/// <summary>
|
||||
/// Check if a directory could be a module folder.
|
||||
/// Check if a directory is likely a localized resources folder.
|
||||
/// </summary>
|
||||
internal static bool IsPossibleModuleDirectory(string dir)
|
||||
/// <param name="dir">Directory to check if it is a possible resource folder.</param>
|
||||
/// <returns>True if the directory name matches a culture.</returns>
|
||||
internal static bool IsPossibleResourceDirectory(string dir)
|
||||
{
|
||||
// We shouldn't be searching in hidden directories.
|
||||
FileAttributes attributes = File.GetAttributes(dir);
|
||||
if (0 != (attributes & FileAttributes.Hidden))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assume locale directories do not contain modules.
|
||||
if (dir.EndsWith(@"\en", StringComparison.OrdinalIgnoreCase) ||
|
||||
dir.EndsWith(@"\en-us", StringComparison.OrdinalIgnoreCase))
|
||||
if (dir.EndsWith(EnCulturePath, StringComparison.OrdinalIgnoreCase) ||
|
||||
dir.EndsWith(EnUsCulturePath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
dir = Path.GetFileName(dir);
|
||||
|
||||
// Use some simple pattern matching to avoid the call into GetCultureInfo when we know it will fail (and throw).
|
||||
if ((dir.Length == 2 && char.IsLetter(dir[0]) && char.IsLetter(dir[1]))
|
||||
||
|
||||
|
@ -55,12 +54,12 @@ namespace System.Management.Automation.Internal
|
|||
// This might not throw on invalid culture still
|
||||
// 4096 is considered the unknown locale - so assume that could be a module
|
||||
var cultureInfo = new CultureInfo(dir);
|
||||
return cultureInfo.LCID == 4096;
|
||||
return cultureInfo.LCID != 4096;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -75,6 +74,7 @@ namespace System.Management.Automation.Internal
|
|||
Queue<string> directoriesToCheck = new Queue<string>();
|
||||
directoriesToCheck.Enqueue(topDirectoryToCheck);
|
||||
|
||||
bool firstSubDirs = true;
|
||||
while (directoriesToCheck.Count > 0)
|
||||
{
|
||||
string directoryToCheck = directoriesToCheck.Dequeue();
|
||||
|
@ -83,7 +83,7 @@ namespace System.Management.Automation.Internal
|
|||
string[] subDirectories = Directory.GetDirectories(directoryToCheck, "*", options);
|
||||
foreach (string toAdd in subDirectories)
|
||||
{
|
||||
if (IsPossibleModuleDirectory(toAdd))
|
||||
if (firstSubDirs || !IsPossibleResourceDirectory(toAdd))
|
||||
{
|
||||
directoriesToCheck.Enqueue(toAdd);
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ namespace System.Management.Automation.Internal
|
|||
catch (IOException) { }
|
||||
catch (UnauthorizedAccessException) { }
|
||||
|
||||
firstSubDirs = false;
|
||||
string[] files = Directory.GetFiles(directoryToCheck, "*", options);
|
||||
foreach (string moduleFile in files)
|
||||
{
|
||||
|
@ -304,17 +305,14 @@ namespace System.Management.Automation.Internal
|
|||
{
|
||||
foreach (var subdirectory in subdirectories)
|
||||
{
|
||||
if (IsPossibleModuleDirectory(subdirectory))
|
||||
if (subdirectory.EndsWith("Microsoft.PowerShell.Management", StringComparison.OrdinalIgnoreCase) ||
|
||||
subdirectory.EndsWith("Microsoft.PowerShell.Utility", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (subdirectory.EndsWith("Microsoft.PowerShell.Management", StringComparison.OrdinalIgnoreCase) ||
|
||||
subdirectory.EndsWith("Microsoft.PowerShell.Utility", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
directoriesToCheck.AddFirst(subdirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
directoriesToCheck.AddLast(subdirectory);
|
||||
}
|
||||
directoriesToCheck.AddFirst(subdirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
directoriesToCheck.AddLast(subdirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +485,7 @@ namespace System.Management.Automation.Internal
|
|||
}
|
||||
}
|
||||
|
||||
string moduleShortName = System.IO.Path.GetFileNameWithoutExtension(modulePath);
|
||||
string moduleShortName = Path.GetFileNameWithoutExtension(modulePath);
|
||||
|
||||
IDictionary<string, CommandTypes> exportedCommands = AnalysisCache.GetExportedCommands(modulePath, testOnly: false, context);
|
||||
|
||||
|
|
|
@ -370,7 +370,7 @@ namespace System.Management.Automation
|
|||
// * and SearchOption.AllDirectories gets all the version directories.
|
||||
string[] directories = Directory.GetDirectories(psModulePath, "*", SearchOption.AllDirectories);
|
||||
|
||||
var possibleModuleDirectories = directories.Where(directory => ModuleUtils.IsPossibleModuleDirectory(directory));
|
||||
var possibleModuleDirectories = directories.Where(directory => !ModuleUtils.IsPossibleResourceDirectory(directory));
|
||||
|
||||
foreach (string directory in possibleModuleDirectories)
|
||||
{
|
||||
|
|
|
@ -10,11 +10,13 @@ Describe "Get-Module -ListAvailable" -Tags "CI" {
|
|||
New-Item -ItemType Directory -Path "$testdrive\Modules\Foo\2.0" -Force > $null
|
||||
New-Item -ItemType Directory -Path "$testdrive\Modules\Bar\Download" -Force > $null
|
||||
New-Item -ItemType Directory -Path "$testdrive\Modules\Zoo\Too" -Force > $null
|
||||
New-Item -ItemType Directory -Path "$testdrive\Modules\Az" -Force > $null
|
||||
|
||||
New-ModuleManifest -Path "$testdrive\Modules\Foo\1.1\Foo.psd1" -ModuleVersion 1.1
|
||||
New-ModuleManifest -Path "$testdrive\Modules\Foo\2.0\Foo.psd1" -ModuleVersion 2.0
|
||||
New-ModuleManifest -Path "$testdrive\Modules\Bar\Bar.psd1"
|
||||
New-ModuleManifest -Path "$testdrive\Modules\Zoo\Zoo.psd1"
|
||||
New-ModuleManifest -Path "$testdrive\Modules\Az\Az.psd1" -ModuleVersion 1.1
|
||||
|
||||
New-Item -ItemType File -Path "$testdrive\Modules\Foo\1.1\Foo.psm1" > $null
|
||||
New-Item -ItemType File -Path "$testdrive\Modules\Foo\2.0\Foo.psm1" > $null
|
||||
|
@ -22,6 +24,7 @@ Describe "Get-Module -ListAvailable" -Tags "CI" {
|
|||
New-Item -ItemType File -Path "$testdrive\Modules\Bar\Download\Download.psm1" > $null
|
||||
New-Item -ItemType File -Path "$testdrive\Modules\Zoo\Zoo.psm1" > $null
|
||||
New-Item -ItemType File -Path "$testdrive\Modules\Zoo\Too\Zoo.psm1" > $null
|
||||
New-Item -ItemType File -Path "$testdrive\Modules\Az\Az.psm1" > $null
|
||||
|
||||
$fullyQualifiedPathTestCases = @(
|
||||
# The current behaviour in PowerShell is that version gets ignored when using Get-Module -FullyQualifiedName with a path
|
||||
|
@ -40,11 +43,13 @@ Describe "Get-Module -ListAvailable" -Tags "CI" {
|
|||
|
||||
It "Get-Module -ListAvailable" {
|
||||
$modules = Get-Module -ListAvailable
|
||||
$modules.Count | Should -Be 4
|
||||
$modules.Count | Should -Be 5
|
||||
$modules = $modules | Sort-Object -Property Name, Version
|
||||
$modules.Name -join "," | Should -BeExactly "Bar,Foo,Foo,Zoo"
|
||||
$modules[1].Version | Should -Be "1.1"
|
||||
$modules[2].Version | Should -Be '2.0'
|
||||
$modules.Name -join "," | Should -BeExactly "Az,Bar,Foo,Foo,Zoo"
|
||||
$modules[0].Version | Should -Be "1.1"
|
||||
$modules[1].Version | Should -Be "0.0.1"
|
||||
$modules[2].Version | Should -Be '1.1'
|
||||
$modules[3].Version | Should -Be '2.0'
|
||||
}
|
||||
|
||||
It "Get-Module <Name> -ListAvailable" {
|
||||
|
@ -58,25 +63,27 @@ Describe "Get-Module -ListAvailable" -Tags "CI" {
|
|||
|
||||
It "Get-Module -ListAvailable -All" {
|
||||
$modules = Get-Module -ListAvailable -All
|
||||
$modules.Count | Should -Be 10
|
||||
$modules.Count | Should -Be 12
|
||||
$modules = $modules | Sort-Object -Property Name, Path
|
||||
$modules.Name -join "," | Should -BeExactly "Bar,Bar,Download,Foo,Foo,Foo,Foo,Zoo,Zoo,Zoo"
|
||||
$modules.Name -join "," | Should -BeExactly "Az,Az,Bar,Bar,Download,Foo,Foo,Foo,Foo,Zoo,Zoo,Zoo"
|
||||
|
||||
$modules[0].ModuleType | Should -BeExactly "Manifest"
|
||||
$modules[1].ModuleType | Should -BeExactly "Script"
|
||||
$modules[2].ModuleType | Should -BeExactly "Script"
|
||||
$modules[3].ModuleType | Should -BeExactly "Manifest"
|
||||
$modules[3].Version | Should -Be "1.1"
|
||||
$modules[2].ModuleType | Should -BeExactly "Manifest"
|
||||
$modules[3].ModuleType | Should -BeExactly "Script"
|
||||
$modules[4].ModuleType | Should -BeExactly "Script"
|
||||
$modules[5].ModuleType | Should -BeExactly "Manifest"
|
||||
$modules[5].Version | Should -Be "2.0"
|
||||
$modules[5].Version | Should -Be "1.1"
|
||||
$modules[6].ModuleType | Should -BeExactly "Script"
|
||||
$modules[7].ModuleType | Should -BeExactly "Script"
|
||||
$modules[7].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Too\Zoo.psm1").Path
|
||||
$modules[8].ModuleType | Should -BeExactly "Manifest"
|
||||
$modules[8].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Zoo.psd1").Path
|
||||
$modules[7].ModuleType | Should -BeExactly "Manifest"
|
||||
$modules[7].Version | Should -Be "2.0"
|
||||
$modules[8].ModuleType | Should -BeExactly "Script"
|
||||
$modules[9].ModuleType | Should -BeExactly "Script"
|
||||
$modules[9].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Zoo.psm1").Path
|
||||
$modules[9].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Too\Zoo.psm1").Path
|
||||
$modules[10].ModuleType | Should -BeExactly "Manifest"
|
||||
$modules[10].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Zoo.psd1").Path
|
||||
$modules[11].ModuleType | Should -BeExactly "Script"
|
||||
$modules[11].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Zoo.psm1").Path
|
||||
}
|
||||
|
||||
It "Get-Module <Name> -ListAvailable -All" {
|
||||
|
@ -93,19 +100,19 @@ Describe "Get-Module -ListAvailable" -Tags "CI" {
|
|||
|
||||
It "Get-Module <Path> -ListAvailable" {
|
||||
$modules = Get-Module "$testdrive\Modules\*" -ListAvailable
|
||||
$modules.Count | Should -Be 4
|
||||
$modules.Count | Should -Be 5
|
||||
$modules = $modules | Sort-Object -Property Name, Version
|
||||
$modules.Name -join "," | Should -BeExactly "Bar,Foo,Foo,Zoo"
|
||||
$modules[1].Version | Should -Be "1.1"
|
||||
$modules[2].Version | Should -Be '2.0'
|
||||
$modules.Name -join "," | Should -BeExactly "Az,Bar,Foo,Foo,Zoo"
|
||||
$modules[2].Version | Should -Be "1.1"
|
||||
$modules[3].Version | Should -Be '2.0'
|
||||
}
|
||||
|
||||
It "Get-Module <Path> -ListAvailable -All" {
|
||||
$modules = Get-Module "$testdrive\Modules\*" -ListAvailable -All
|
||||
$modules.Count | Should -Be 5
|
||||
$modules.Count | Should -Be 6
|
||||
$modules = $modules | Sort-Object -Property Name, Path
|
||||
$modules.Name -join "," | Should -BeExactly "Bar,Foo,Foo,Zoo,Zoo"
|
||||
$modules[3].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Too\Zoo.psm1").Path
|
||||
$modules.Name -join "," | Should -BeExactly "Az,Bar,Foo,Foo,Zoo,Zoo"
|
||||
$modules[4].Path | Should -BeExactly (Resolve-Path "$testdrive\Modules\Zoo\Too\Zoo.psm1").Path
|
||||
}
|
||||
|
||||
It "Get-Module -FullyQualifiedName <FullyQualifiedName> -ListAvailable" {
|
||||
|
|
Loading…
Reference in a new issue