New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add -Name, -NoUserOverrides and -ListAvailable parameters to Get-Culture cmdlet #7702
Conversation
d7afc9a
to
64e1f70
Compare
/cc @mklement0 |
private const string ListAvailableParameterSet = "ListAvailable"; | ||
|
||
/// <summary> | ||
/// Gets and sets the specified culture. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an aside: I don't think it's worth reflecting that the property representing the parameter is read/write (that can easily be gleaned from the code) - just stating the purpose of the parameter should be sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment should start with "Gets and sets" to fix CodeFactor issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, but in this context such comments are more confusing than helpful. I know nothing about CodeFactor: does this particular rule a default rule, or one that was specifically turned on for this repo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Native language is very flexible - I reworded the comment.
CodeFactor is a service. It uses StypeCop static analyzer too. Yes, we can to turn in/out rules. Currently we have some PRs to turn StypeCop and editors settings. Plan is to complete the work after 6.1 GA.
src/Microsoft.PowerShell.Commands.Utility/commands/utility/GetCultureCommand.cs
Outdated
Show resolved
Hide resolved
/// <summary> | ||
/// Output the current Culture info object. | ||
/// </summary> | ||
protected override void BeginProcessing() | ||
protected override void EndProcessing() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to do this in EndProcessing
vs ProcessRecord
? Typically, EndProcessing
is used for cleanup after the pipeline has completed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially we do not support pipelines and using EndProcessing() was ok. Currently the cmdlet was enhanced to support pipelines and the code was moved to ProcessRecord().
I discovered that Get-Culture "abc" return CultureInfo object - there is no exception internally. Seems it is "by design" and based on OS behavior. See https://github.com/dotnet/corefx/issues/1669. Perhaps we should add this in documentation. |
@iSazonov: That is unfortunate; |
I see. I'll skip the test on Linux and MacOs. Should I add a comment that it is a bug in .Net Core? Is there a tracking issue? |
I would personally consider it a bug, but I've only read the CoreFx issue that you linked to; from there I came across https://github.com/dotnet/corefx/issues/6374#issuecomment-245706306, which promises a fix on Linux, but hat seemingly never happened. May be worth opening a new issue. |
@mklement0 Thanks! I added a comment there. |
$ciArray[0] | Should -BeOfType [CultureInfo] | ||
} | ||
|
||
It "Should write an error on unsupported culture name" -Skip:(!$isWindows) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest adding the issue link as a comment for -Skip
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the test - now it throw on Unix-es too. Link to useful comment added too.
/// Gets or sets culture names for which CultureInfo values are returned. | ||
/// </summary> | ||
[Parameter(ParameterSetName = NameParameterSet, Position = 0, ValueFromPipeline = true)] | ||
[ValidateNotNull] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be ValidateNotNullOrEmpty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For empty string name InvariantCulture
is returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iSazonov - I think that behavior's too subtle.
Additionally, the ProcessRecord doesn't match the class comment (Return's the thread's current culture). In short, reviewing the code appears to not support getting the current culture.
NOTE: Line 40 that compares Name to null 'looks' like dead code since name must be non-null for the Name parameter set. Having an explicit or fall through 'default' case statement will make this clearer.
I suggest the following:
1: Retain the original behavior explicitly
Set the DefaultParameterSetName to 'default' and return the thread's current culture.
2: Name parameter set
Either clearly document that an empty string returns InvariantCulture or don't allow empty strings and require explicit names.
3: ListAvailable
As implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I too think that ""
is obscure and suggest requiring explicit use of Invariant-Culture
, i.e.:
Get-Culture Invariant-Culture
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 - Fixed.
2- Let's consider the scenario - script asks user to input a culture, user press Enter to choose "Default". Without user typing the script get empty string as "default". I guess CoreFX consider InvariantCulture as default if culture is unknown or not selected. We use InvariantCulture widely in PowerShell code too. So allowing empty string in Get-Culture looks good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re 2: Curiously, the empty string is not just a placeholder that signals the intent to retrieve the invariant culture when you call .GetCultureInfo()
, it is the actual value of the .Name
property of the culture-info object returned - so I guess it makes sense to surface that.(Unlike what I thought earlier, "Invariant-Culture"
doesn't actually work; on Unix it implicitly creates an ad-hoc culture, on Windows it breaks.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add a comment about this in the code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
@PowerShell/powershell-committee reviewed this and continue to be consistent in our thinking that for literals, a non-terminating error should be returned, and for filtering/wildcards, it should return nothing if not found. Should also consider adding a Test-Culture cmdlet. |
Sorry - my earlier statement was incorrect: The - questionable - logic of the
What constitutes a formally correct culture name is platform-specific, however:
|
I guess we can work around this by validating names against @SteveL-MSFT: Currently, the PR has no wildcard support for |
We have #7562. I suggest to explicitly track all approved Test-* cmdlets there. |
@mklement0 I think it is ok to follow .Net Core behavior "as is" - if they really think it's right, then we can hardly do better. |
@iSazonov: Since we're not just providing access to the underlying CoreFx functionality, but packaging it in a PowerShell-appropriate way, I don't think we're obligated to surface the functionality as-is. I have yet to hear a good reason for the CoreFx behavior (there may be one, but I haven't heard it), and users who really want to implicitly create cultures such as |
@mklement0 With |
/// Gets or sets culture names for which CultureInfo values are returned. | ||
/// </summary> | ||
[Parameter(ParameterSetName = NameParameterSet, Position = 0, ValueFromPipeline = true)] | ||
[ValidateNotNull] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iSazonov - I think that behavior's too subtle.
Additionally, the ProcessRecord doesn't match the class comment (Return's the thread's current culture). In short, reviewing the code appears to not support getting the current culture.
NOTE: Line 40 that compares Name to null 'looks' like dead code since name must be non-null for the Name parameter set. Having an explicit or fall through 'default' case statement will make this clearer.
I suggest the following:
1: Retain the original behavior explicitly
Set the DefaultParameterSetName to 'default' and return the thread's current culture.
2: Name parameter set
Either clearly document that an empty string returns InvariantCulture or don't allow empty strings and require explicit names.
3: ListAvailable
As implemented.
@iSazonov: Postponing wildcard support sounds good to me, but I do think we should get clarity on whether we truly want to support calls such as I see only down-sides to surfacing the baffling CoreFx functionality as-is. Conversely, if we restrict allowed names to the ones reported by |
I don't know whether we truly want. The breaking change will be in grace arae - I'd expect users will use right culture names. On the other hand, it is not clear what the filter should be. from the CoreFX discussion we know that there may be some special logic. There can be a situation similar we see with encodings - we get a short list but really supported encodings there is more. |
@SteveL-MSFT @mklement0 The PR is ready for final review. |
/// Gets or sets culture names for which CultureInfo values are returned. | ||
/// </summary> | ||
[Parameter(ParameterSetName = NameParameterSet, Position = 0, ValueFromPipeline = true)] | ||
[ValidateNotNull] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add a comment about this in the code
} | ||
else | ||
{ | ||
ci = CultureInfo.GetCultureInfo(cultureName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, based on @PowerShell/powershell-committee discussion we should only return cultures from the AllCultures list. Creation is out of scope of this PR.
|
||
It "Should have `$PSCulture variable be equivalent to (Get-Culture).Name" { | ||
|
||
(Get-Culture).Name | Should -Be $PsCulture |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the test description, it would seem that this should be:
$PSCulture | Should -BeExactly (Get-Culture).Name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the order is right because the file is for Get-Culture tests and we should correct the description.
But I'd expect that we check $Host.CurrentCulture instead of $PsCulture
.
On other side, we haven't tests for special variables at all.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine changing the test description to match the test and adding separate test for $PSCulture
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
It "Should return specified cultures with '-Name' parameter" { | ||
|
||
$ciArray = Get-Culture "", "ru-RU" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we should have a specific test case to handle invariant culture making it clear what is being validated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the check and comment.
{ | ||
if (NoUserOverrides && string.Equals(cultureName, Host.CurrentCulture.Name, StringComparison.CurrentCultureIgnoreCase)) | ||
{ | ||
ci = new CultureInfo(cultureName, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use named params here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
case CurrentCultureParameterSet: | ||
if (NoUserOverrides) | ||
{ | ||
ci = CultureInfo.GetCultureInfo(Host.CurrentCulture.LCID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use .Name
instead of .LCID
, and we should probably do the same for all tests.
"LCIDs are being deprecated, and implementers are strongly encouraged to use locale names instead. LCIDs can be used for backward compatibility, but as noted in section 2.2.1, there is no guarantee of LCID uniqueness when used with valid locale names not otherwise associated with an LCID. " - from "[MS-LCID]: Windows Language Code Identifier (LCID) Reference" - https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/[MS-LCID].pdf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the change is not related to and not critical for the PR. We can postpone the change until CoreFX obsolete the API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[cultureinfo]::getcultures('allcultures') | group-object lcid | ? count -gt 1
will tell you that hundreds of predefined cultures share the same LCID, so this fix is an absolute must.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
{ | ||
foreach (var cultureName in Name) | ||
{ | ||
if (NoUserOverrides && string.Equals(cultureName, Host.CurrentCulture.Name, StringComparison.CurrentCultureIgnoreCase)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be !NoUserOverrides
and the 2nd CultureInfo
constructor argument below should be true
(or omitted), but you could just use Host.CurrentCulture
, which also reflects the overrides.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@SteveL-MSFT Please point me comments if I missed something. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@mklement0 Please update your review. |
Reopen to restart all CIs. |
@mklement0 Many thanks for great help! |
My pleasure, @iSazonov, thanks for implementing it all. |
…ure cmdlet (PowerShell#7702) Add new parameters in Get-Culture cmdlet: -Name - to allow retrieving a specific culture -NoUserOverrides - ignore user changes for current culture -ListAvalable - to allow retrieving all cultures supported on the platform
PR Summary
Address #3832
Add new parameters in Get-Culture cmdlet:
-Name
- to allow retrieving a specific culture-NoUserOverrides
- ignore user changes for current culture-ListAvalable
- to allow retrieving all cultures supported on the platformDocumentation
Please see https://github.com/dotnet/corefx/issues/6374#issuecomment-418827420 and following comments.
In short .Net Core accept all culture names in BCP-47 format and then delegate to OS so result depends on OS behavior and differ on different OS-s.
PR Checklist
.h
,.cpp
,.cs
,.ps1
and.psm1
files have the correct copyright headerWIP:
to the beginning of the title and remove the prefix when the PR is ready.[feature]
if the change is significant or affects feature tests