-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Experimental Feature: Provide Unix stat information in filesystem output #11042
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
Experimental Feature: Provide Unix stat information in filesystem output #11042
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i rewrote this method using a char array.
} | ||
|
||
// We need a way to convert a DateTime to a unix date.j |
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.
// 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. |
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!
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be:
$skipTest = -not $EnabledExperimentalFeatures.Contains('PSUnixFileStat')
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!
…array of chars A number of smaller fixes suggested by review.
internal static class Unix | ||
{ | ||
// Please note that `Win32Exception(Marshal.GetLastWin32Error())` |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cs.AccessTime = new DateTime(1970, 1, 1).AddSeconds(css.AccessTime).ToLocalTime(); | |
cs.AccessTime = DateTime.UnixEpoch.AddSeconds(css.AccessTime).ToLocalTime(); |
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.
And below
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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?"
@@ -701,6 +1063,94 @@ internal static UnixTm DateTimeToUnixTm(DateTime date) | |||
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] | |||
internal static extern int GetInodeData([MarshalAs(UnmanagedType.LPStr)]string path, | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
.
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.
done!
#region UnixStat | ||
|
||
|
||
if (ExperimentalFeature.IsEnabled("PSUnixFileStat")) |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could squash this into the previous condition with an &&
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.
done
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use named parameter in place of null
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
# 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider setting PSDefaultParameterValue 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.
done
var commonStat = Platform.Unix.GetLStat(path); | ||
result.AddOrSetProperty("UnixStat", commonStat); | ||
} | ||
catch |
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.
Do you want to catch a specific exception 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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a comment
$group = (/bin/ls -ld $testFile).split(" ",[System.StringSplitOptions]"RemoveEmptyEntries")[3] | ||
$i.Group | Should -Be $Group | ||
} | ||
|
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.
extra line
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
…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 namedUnixStat
which includes a common expression of thestat(2)
API from the underlying Unix type system. The native calls in thepowershell-native
assembly have createdThe output from
Get-ChildItem
should 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-ChildItem
since it's different from/bin/ls -l
output. 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
children
view with format-table:PR Checklist
.h
,.cpp
,.cs
,.ps1
and.psm1
files have the correct copyright headerWIP:
or[ WIP ]
to the beginning of the title (theWIP
bot will keep its status check atPending
while the prefix is present) and remove the prefix when the PR is ready.