Allow partial culture matching in Update-Help (#18037)

This commit is contained in:
Dominik Kaszewski
2023-05-09 09:46:59 -07:00
committed by GitHub
parent 7888196b87
commit 270f8f1be7
5 changed files with 108 additions and 33 deletions
@@ -1514,11 +1514,14 @@ namespace System.Management.Automation.Internal
internal static bool UseDebugAmsiImplementation;
internal static bool BypassAppLockerPolicyCaching;
internal static bool BypassOnlineHelpRetrieval;
internal static bool ThrowHelpCultureNotSupported;
internal static bool ForcePromptForChoiceDefaultOption;
internal static bool NoPromptForPassword;
internal static bool ForceFormatListFixedLabelWidth;
// Update-Help tests
internal static bool ThrowHelpCultureNotSupported;
internal static CultureInfo CurrentUICulture;
// Stop/Restart/Rename Computer tests
internal static bool TestStopComputer;
internal static bool TestWaitStopComputer;
@@ -557,7 +557,8 @@ namespace Microsoft.PowerShell.Commands
#endif
catch (UpdatableHelpSystemException e)
{
if (e.FullyQualifiedErrorId == "HelpCultureNotSupported")
if (e.FullyQualifiedErrorId == "HelpCultureNotSupported"
|| e.FullyQualifiedErrorId == "UnableToRetrieveHelpInfoXml")
{
installed = false;
@@ -672,7 +673,7 @@ namespace Microsoft.PowerShell.Commands
}
// Culture check
if (!newHelpInfo.IsCultureSupported(culture))
if (!newHelpInfo.IsCultureSupported(culture.Name))
{
throw new UpdatableHelpSystemException("HelpCultureNotSupported",
StringUtil.Format(HelpDisplayStrings.HelpCultureNotSupported,
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Management.Automation.Internal;
using System.Text;
@@ -37,6 +39,44 @@ namespace System.Management.Automation.Help
/// Supported culture.
/// </summary>
internal CultureInfo Culture { get; set; }
/// <summary>
/// Enumerates fallback chain (parents) of the culture, including itself.
/// </summary>
/// <param name="culture">Culture to enumerate</param>
/// <example>
/// Examples:
/// en-GB => { en-GB, en }
/// zh-Hans-CN => { zh-Hans-CN, zh-Hans, zh }.
/// </example>
/// <returns>An enumerable list of culture names.</returns>
internal static IEnumerable<string> GetCultureFallbackChain(CultureInfo culture)
{
// We use just names instead because comparing two CultureInfo objects
// can fail if they are created using different means
while (culture != null)
{
if (string.IsNullOrEmpty(culture.Name))
{
yield break;
}
yield return culture.Name;
culture = culture.Parent;
}
}
/// <summary>
/// Checks if a culture is supported.
/// </summary>
/// <param name="cultureName">Name of the culture to check.</param>
/// <returns>True if supported, false if not.</returns>
internal bool IsCultureSupported(string cultureName)
{
Debug.Assert(cultureName != null, $"{nameof(cultureName)} may not be null");
return GetCultureFallbackChain(Culture).Any(fallback => fallback == cultureName);
}
}
/// <summary>
@@ -99,22 +139,12 @@ namespace System.Management.Automation.Help
/// <summary>
/// Checks if a culture is supported.
/// </summary>
/// <param name="culture">Culture to check.</param>
/// <param name="cultureName">Name of the culture to check.</param>
/// <returns>True if supported, false if not.</returns>
internal bool IsCultureSupported(CultureInfo culture)
internal bool IsCultureSupported(string cultureName)
{
Debug.Assert(culture != null);
foreach (CultureSpecificUpdatableHelp updatableHelpItem in UpdatableHelpItems)
{
if (string.Equals(updatableHelpItem.Culture.Name, culture.Name,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
Debug.Assert(cultureName != null, $"{nameof(cultureName)} may not be null");
return UpdatableHelpItems.Any(item => item.IsCultureSupported(cultureName));
}
/// <summary>
@@ -294,19 +294,13 @@ namespace System.Management.Automation.Help
{
CultureInfo culture = CultureInfo.CurrentUICulture;
while (culture != null)
// Allow tests to override system culture
if (InternalTestHooks.CurrentUICulture != null)
{
if (string.IsNullOrEmpty(culture.Name))
{
yield break;
}
yield return culture.Name;
culture = culture.Parent;
culture = InternalTestHooks.CurrentUICulture;
}
yield break;
return CultureSpecificUpdatableHelp.GetCultureFallbackChain(culture);
}
#region Help Metadata Retrieval
@@ -594,13 +588,9 @@ namespace System.Management.Automation.Help
if (!string.IsNullOrEmpty(currentCulture))
{
IEnumerable<WildcardPattern> patternList = SessionStateUtilities.CreateWildcardsFromStrings(
globPatterns: new[] { currentCulture },
options: WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant);
for (int i = 0; i < updatableHelpItem.Length; i++)
{
if (SessionStateUtilities.MatchesAnyWildcardPattern(updatableHelpItem[i].Culture.Name, patternList, true))
if (updatableHelpItem[i].IsCultureSupported(currentCulture))
{
helpInfo.HelpContentUriCollection.Add(new UpdatableHelpUri(moduleName, moduleGuid, updatableHelpItem[i].Culture, uri));
}
@@ -30,7 +30,7 @@ function UpdateHelpFromLocalContentPath {
throw "Unable to find help content at '$helpContentPath'"
}
# Test files are 'en-US', set explicit culture so test does not help on non-US systems
# Test files are 'en-US', set explicit culture so test does not fail on non-US systems
Update-Help -Module $ModuleName -SourcePath $helpContentPath -UICulture 'en-US' -Force -ErrorAction Stop -Scope $Scope
}
@@ -635,3 +635,54 @@ Describe 'help renders when using a PAGER with a space in the path' -Tags 'CI' {
help Get-Command | Should -Be "R2V0LUNvbW1hbmQ="
}
}
Describe 'Update-Help allows partial culture matches' -Tags 'CI' {
BeforeAll {
function Test-UpdateHelpAux($UICulture, $Pass)
{
# If null (in system culture tests), omit entirely
$CultureArg = $UICulture ? @{ UICulture = $UICulture } : @{}
$Args = @{
Module = 'Microsoft.PowerShell.Core'
SourcePath = Join-Path $PSScriptRoot 'assets'
Force = $true
ErrorAction = $Pass ? 'Stop' : 'SilentlyContinue'
ErrorVariable = 'ErrorVariable'
}
Update-Help @Args @CultureArg
if (-not $Pass) {
$ErrorVariable | Should -Match 'Failed to update Help for the module.*'
}
}
}
AfterEach {
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('CurrentUICulture', $null)
}
It 'Checks culture match against en-US: <UICulture>' -TestCases @(
@{ UICulture = 'en-US' }
@{ UICulture = 'en' }
@{ UICulture = 'en-GB'; Pass = $false }
@{ UICulture = 'de-DE'; Pass = $false }
) {
param($UICulture, $Pass = $true)
Test-UpdateHelpAux $UICulture $Pass
}
# When using system culture, "en-GB" will use "en" as fallback, so passes
It 'Checks system culture match against en-US: <UICulture>' -TestCases @(
@{ UICulture = 'en-US' }
@{ UICulture = 'en' }
@{ UICulture = 'en-GB' }
@{ UICulture = 'de-DE'; Pass = $false }
) {
param($UICulture, $Pass = $true)
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('CurrentUICulture', [System.Globalization.CultureInfo]::new($UICulture))
Test-UpdateHelpAux $null $Pass
}
}