Experimental Feature: Provide Unix stat information in filesystem output#11042
Experimental Feature: Provide Unix stat information in filesystem output#11042adityapatwardhan merged 18 commits intoPowerShell:masterfrom
Conversation
It includes the new common Unix stat methods.
| /// <returns>The mode converted into a Unix style string similar to the output of ls.</returns> | ||
| public string GetModeString() | ||
| { | ||
| StatMask[] permissions = new StatMask[] |
There was a problem hiding this comment.
Can this be defined statically? would reduce allocations i think.
| }; | ||
|
|
||
| // start the mode string with the ItemType | ||
| System.Text.StringBuilder sb = new System.Text.StringBuilder(); |
There was a problem hiding this comment.
The length of the output string is fixed to 10 i guess, so we should initialize the string builder with 10 as the capacity.
There was a problem hiding this comment.
i rewrote this method using a char array.
| internal int tm_isdst; | ||
| } | ||
|
|
||
| // We need a way to convert a DateTime to a unix date.j |
There was a problem hiding this comment.
| // We need a way to convert a DateTime to a unix date.j | |
| // We need a way to convert a DateTime to a unix date. |
src/System.Management.Automation/engine/TypeTable_Types_Ps1Xml.cs
Outdated
Show resolved
Hide resolved
| $experimentalFeatureName = "PSUnixFileStat" | ||
| $skipTest = $true | ||
| if ( Get-ExperimentalFeature -Name $experimentalFeatureName ) { | ||
| $skipTest = $false | ||
| } |
There was a problem hiding this comment.
This can be:
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSUnixFileStat')
…array of chars A number of smaller fixes suggested by review.
| /// <summary>Unix specific implementations of required functionality.</summary> | ||
| internal static class Unix | ||
| { | ||
| // Please note that `Win32Exception(Marshal.GetLastWin32Error())` |
There was a problem hiding this comment.
It might be worth either moving this comment or putting a newline between it and the dictionary fields to imply its relevance throughout the class.
I know the linter doesn't like the second suggestion, but I feel strongly that the linter is wrong about that. This is a really helpful comment, but applies generally within the class, while still being an implementation detail (so shouldn't be in something like <remarks/>)
There was a problem hiding this comment.
yah - I moved this comment all around to get it through code factor. I can try a different location :)
There was a problem hiding this comment.
Maybe we can add it in a <remarks> field in an XML comment for the class itself?
| modeCharacters[offset] = '-'; | ||
| } | ||
|
|
||
| offset++; |
There was a problem hiding this comment.
If there's an offset++ here, would it make sense to use a double indexed for () loop instead? That way rather than nesting ifs and elseifs you could just continue.
| foreach (StatMask permission in permissions) | ||
| { | ||
| // determine whether we are setuid, sticky, or the usual rwx. | ||
| if ((Mode & (int)permission) == (int)permission) |
There was a problem hiding this comment.
Actually, is there a way to make this a switch? That seems like it would be the most natural approach/how C does it.
There was a problem hiding this comment.
all the examples I could find (and I only looked for a couple) they do something similar to what I have using if/else (freebsd, gnu)
| public string GetUserName() | ||
| { | ||
| string username; | ||
| if (usernameCache.TryGetValue(UserId, out username)) |
There was a problem hiding this comment.
| if (usernameCache.TryGetValue(UserId, out username)) | |
| if (usernameCache.TryGetValue(UserId, out string username)) |
| /// <returns>The user name.</returns> | ||
| public string GetUserName() | ||
| { | ||
| string username; |
There was a problem hiding this comment.
| string username; |
| cs.GroupId = css.GroupId; | ||
| cs.HardlinkCount = css.HardlinkCount; | ||
| cs.Size = css.Size; | ||
| cs.AccessTime = new DateTime(1970, 1, 1).AddSeconds(css.AccessTime).ToLocalTime(); |
There was a problem hiding this comment.
| cs.AccessTime = new DateTime(1970, 1, 1).AddSeconds(css.AccessTime).ToLocalTime(); | |
| cs.AccessTime = DateTime.UnixEpoch.AddSeconds(css.AccessTime).ToLocalTime(); |
| public int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ | ||
| public int tm_isdst; /* Daylight saving time */ | ||
| /// <summary>Seconds (0-60).</summary> | ||
| internal int tm_sec; |
There was a problem hiding this comment.
Any reason for changing these to internal? I know it's done elsewhere, but usually my reasoning goes like "If this type were public, should this field be visible?"
| out UInt64 device, out UInt64 inode); | ||
|
|
||
| /// <summary> | ||
| /// This is a struct from getcommonstat.h in the native library. It's a synthetic construct of the Unix stat |
There was a problem hiding this comment.
Could you reword synthetic construct? It initially confused me until I realised we're saying this struct doesn't occur anywhere like this, but this type represents the maximal union of all structs in the wild.
| #region UnixStat | ||
|
|
||
|
|
||
| if (ExperimentalFeature.IsEnabled("PSUnixFileStat")) |
There was a problem hiding this comment.
We could cache this, especially since it's an engine experimental feature, so it can't be toggled once PS has started
There was a problem hiding this comment.
Caching not required for perf reasons. I believe changes to all engine experimental features need a restart of PS.
| if (ExperimentalFeature.IsEnabled("PSUnixFileStat")) | ||
| { | ||
| // Add a commonstat structure to file system objects | ||
| if (ProviderInfo.ImplementingType == typeof(Microsoft.PowerShell.Commands.FileSystemProvider)) |
There was a problem hiding this comment.
Could squash this into the previous condition with an &&
Move comment around to a hopefully acceptable location Change language which describes the new common stat structure.
| } | ||
| catch | ||
| { | ||
| result.AddOrSetProperty("UnixStat", null); |
There was a problem hiding this comment.
use named parameter in place of null
| # if PSUnixFileStat is converted from an experimental feature, these tests will need to be changed | ||
| BeforeAll { | ||
| $experimentalFeatureName = "PSUnixFileStat" | ||
| $skipTest = -not $EnabledExperimentalFeatures.Contains($experimentalFeatureName) |
There was a problem hiding this comment.
Consider setting PSDefaultParameterValue for Skip
| var commonStat = Platform.Unix.GetLStat(path); | ||
| result.AddOrSetProperty("UnixStat", commonStat); | ||
| } | ||
| catch |
There was a problem hiding this comment.
Do you want to catch a specific exception here?
There was a problem hiding this comment.
no, any problem means that we can't add the property, so don't. I'll add a comment
There was a problem hiding this comment.
added a comment
| $group = (/bin/ls -ld $testFile).split(" ",[System.StringSplitOptions]"RemoveEmptyEntries")[3] | ||
| $i.Group | Should -Be $Group | ||
| } | ||
|
|
…t when adding UnixStat. Fix a couple of small things in the tests, change to use PSDefaultParameterValue rather than using individual skip parameters
|
Hello @adityapatwardhan! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
|
🎉 Handy links: |
PR Summary
This PR provides new behavior, as experimental feature
PSUnixFileStat, to include data from the Unix stat API in the output of the file system provider to facilitate a more Unix-like file listing. It adds a new note property in the filesystem provider namedUnixStatwhich includes a common expression of thestat(2)API from the underlying Unix type system. The native calls in thepowershell-nativeassembly have createdThe output from
Get-ChildItemshould look something like this:The username and groupname are retrieved at the time of formatting to reduce the number of PInvokes required.
PR Context
I've been somewhat frustrated with viewing the output of
Get-ChildItemsince it's different from/bin/ls -loutput. This is an attempt to improve the experience with regard to the file system provider when running on a non-Windows platforms.The old format is still available by selecting the
childrenview with format-table:PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.