Skip to content
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

Adds a .ResolvedTarget Property to File-System Items to Reflect a Symlink's Target as FileSystemInfo #16490

Merged
merged 21 commits into from Jan 21, 2022

Conversation

hammy275
Copy link
Contributor

@hammy275 hammy275 commented Nov 19, 2021

PR Summary

This PR addresses issue #13366 , adding the ability for users to access a ResolvedTarget property on file and folder items, which returns a string representation of a path, depending on the type of file/folder:

  • If the file/folder is not a symbolic link, ResolvedTarget will return a string referring to itself.
  • If the file/folder is a symbolic link that points to a file/folder that currently exists, ResolvedTarget will return a string referring to the file/folder that the symbolic link points to.
  • If the file/folder is a symbolic link that points to a file that does not exist, ResolvedTarget returns a string referring to the broken destination.

PR Context

This PR mainly addresses the problems described in #13366 , mainly that there is no easy way to resolve the path of a file if said file has a chance of being a symbolic link (and as a result, points to a different file in the end). This PR addresses this with the ResolvedTarget property, which points to "the actual file" whether the file being referenced is a symbolic link or not.

PR Checklist

@ghost
Copy link

ghost commented Nov 19, 2021

CLA assistant check
All CLA requirements met.

@ghost ghost added the Review - Needed The PR is being reviewed label Nov 26, 2021
@ghost
Copy link

ghost commented Nov 26, 2021

This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days.
Maintainer, please provide feedback and/or mark it as Waiting on Author

@iSazonov iSazonov added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label Nov 26, 2021
@iSazonov
Copy link
Collaborator

@hammy3502 Please look test fails.

@mklement0 Could you please review? Is this addressed a behavior you requested?

@ghost ghost removed the Review - Needed The PR is being reviewed label Nov 26, 2021
@hammy275
Copy link
Contributor Author

hammy275 commented Dec 2, 2021

My apologies for the unit tests! The PR should be good to go now. The one failing unit test here looks to be from upstream from when I last rebased, rather than this PR.

EDIT: Looks like the unit tests have all passed; the PR should be good to go!

@iSazonov
Copy link
Collaborator

iSazonov commented Dec 2, 2021

/azp restart PowerShell-CI-macos

@azure-pipelines

This comment has been minimized.

@iSazonov

This comment has been minimized.

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Member

@anamnavi anamnavi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just had one recommendation to remove extra newline

@hammy275
Copy link
Contributor Author

hammy275 commented Dec 11, 2021

It looks like the failed tests are from outside the scope of this PR, so we should still be good to merge. For clarification, all of the tests passed before 9c1b43f, which just removed an empty newline.

EDIT: Looks like the failing unit tests were re-ran, and are good to go now!

{
if (instance.BaseObject is FileSystemInfo fileSysInfo)
{
FileSystemInfo symbTarget = fileSysInfo.ResolveLinkTarget(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FileSystemInfo.ResolveLinkTarget may throw exception in various cases, such as when the current file system doesn't support reparsing point. The Target and FileSystemInfo.LinkedTarget don't throw, so we shouldn't throw either. Please handle the exception and return null in that case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is a negative effects from the throw? Should we really mask the exceptions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When calling the method on a file on a USB drive or micro sd drive, it will fail because the underlying filesystem doesn't support reparsing point. However, the behavior in that case should be returning the full path of the file.

Actually, this scenario should be handled, meaning when exception happens, it should decide when to return the FullName of the current FileSystemInfo, and when to return null.
[edited] For example, when the file is on a USB drive, ResolvedTarget should return the FullName of the file, even though exception will be thrown from fileSysInfo.ResolveLinkTarget(true).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would weird behavior in formatting output - if user see Target and LinkType properties are "empty" but ResolvedTarget is FullName.
And if I remember correctly .Net ResolveLinkTarget can return partially resolved path. https://github.com/dotnet/runtime/blob/12a8819eee9865eb38bca6c05fdece1053102854/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs#L621-L627

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior I describe is what was asked from the issue:

If the item at hand isn't a symlink / reparse point, simply report its own full path - this allows unified treatment of symlinks and non-symlinks, as a simple way to get an item's full path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm about to push a commit that wraps a try-catch around the ResolveLinkTarget call and returning null, however I'm not sure in what situation ResolveLinkTarget would throw an exception and want to return FullName. It cleanly returns null when encountering something that isn't a symlink, and flash drives (by flashdrives, I'm assuming you mean the usage of FAT32/exFAT here) don't seem to support symlinks in any capacity. Am I missing something here? Thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to return FullName only if the FileSystemInfo is just a regular file/directory instead of a link.

Looking more into it, I found on portable drive with exFAT file system, ResolveLinkTarget(false) throws while ResolveLinkTarget(true) doesn't throw (see code here). So, maybe we don't really need the try / catch (IOException) here.

So, maybe we can do the following:

  1. if ResolveLinkTarget(true) returns non-null value, just return that value. (I see you check on symbTarget.Exists here, but could it even be possible that the method returns a non-null value, but it doesn't exist?)
  2. if ResolveLinkTarget(true) returns null value, assuming that means it's not a link, and thus return the FullName or the current FileSystemInfo depending on what we want for return type.
  3. if ResolveLinkTarget(true) throws, then we assume that means it could be link, but something is wrong when resolving it. We just let the exception propagate in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the docstring for ResolveLinkTarget, it looks like we do need to check if it exists:

Returns: A System.IO.FileSystemInfo instance if the link exists, independently if the target exists or not

Besides that, the commit I mentioned earlier and the ones I just pushed should match the requested behavior!

@ghost ghost added the Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept label Dec 15, 2021
@daxian-dbw daxian-dbw added the Review - Committee The PR/Issue needs a review from the PowerShell Committee label Dec 15, 2021
@daxian-dbw
Copy link
Member

daxian-dbw commented Dec 15, 2021

@PowerShell/powershell-committee We need the committee to review the issue and PR on 2 behaviors of the proposed ResolvedTarget property:

  1. when the file or directory is not a symlink / reparse point, whether it should report its own full path, or return null. See Adds a .ResolvedTarget Property to File-System Items to Reflect a Symlink's Target as FileSystemInfo #16490 (comment) for the discussion.
  2. whether the parameter type of the proposed property to be FileSystemInfo or string. see Adds a .ResolvedTarget Property to File-System Items to Reflect a Symlink's Target as FileSystemInfo #16490 (comment) for the discussion.

@ghost ghost added the Stale label Dec 30, 2021
@ghost
Copy link

ghost commented Dec 30, 2021

This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 15 days. It will be closed if no further activity occurs within 10 days of this comment.

@hammy275
Copy link
Contributor Author

Apologies for the slow response! I'll do my best to have the changes back within a couple days!

@ghost ghost removed Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept Stale labels Dec 31, 2021
@daxian-dbw
Copy link
Member

@hammy3502 Thanks for your reply. I responded to your comments, and let's wait on the committee to decide the return type.

@hammy275
Copy link
Contributor Author

hammy275 commented Jan 4, 2022

@daxian-dbw Thank you so much! I handled the two threads you responded to, and I'll be eagerly awaiting a response from the committee! :)

@SteveL-MSFT
Copy link
Member

@PowerShell/powershell-committee reviewed this:

  1. We agreed that .ResolvedTarget should always have a value that is the full path regardless if the item is a link. Users should rely on .Attributes to determine if an item is a link or not. By having this property always have a value, users won't need to check if it's $null and can also make it easier to format without conditionals.

  2. We also agreed that for consistency and also it's easy to convert the string path to a FileSystemInfo object and most users may not want to incur the additional memory to allocate that object, it makes sense for .ResolvedTarget to be a string.

@iSazonov iSazonov added the Documentation Needed in this repo Documentation is needed in this repo label Jan 19, 2022
@iSazonov
Copy link
Collaborator

iSazonov commented Jan 19, 2022

@hammy3502 Please update the PR description to reflect new logic is implemented and open new issue in Documentation repository https://github.com/MicrosoftDocs/PowerShell-Docs.

GitHub
The official PowerShell documentation sources. Contribute to MicrosoftDocs/PowerShell-Docs development by creating an account on GitHub.

@hammy275
Copy link
Contributor Author

@iSazonov I've updated the PR description, however I can't seem to find a page to propose any needed documentation changes (there doesn't appear to be any pages for FileInfo/DirectoryInfo that I could find). Are there any pages you'd recommend be updated so I can open an issue? Thank you so much!

@iSazonov
Copy link
Collaborator

I've updated the PR description

I don't see all cases covered in #16490 (comment)

I can't seem to find a page to propose any needed documentation changes

Since it is new addition I think it should be documented. If PowerShell documentation hasn't appropriate pages you can new doc issue as "idea" in doc repo.

@iSazonov
Copy link
Collaborator

@daxian-dbw How could we re-run Update cgmanifest CI?

@daxian-dbw
Copy link
Member

daxian-dbw commented Jan 19, 2022

I have no idea. I guess it's stuck for some reason, and we may have to close the PR and then re-open.
I just tried re-running the job in the Actions tab. Will see if that helps.
https://github.com/PowerShell/PowerShell/actions/runs/1714599480

@iSazonov
Copy link
Collaborator

@daxian-dbw Thanks!

This cgmanifest is reminiscent of the Files.wxs story. At first we had to update it manually every time. After that exhausted everyone, the update became automatic. 😄 I hope to see auto update soon!

@iSazonov
Copy link
Collaborator

@daxian-dbw The action was finished but not reported again. 😟

@daxian-dbw daxian-dbw closed this Jan 19, 2022
@daxian-dbw daxian-dbw reopened this Jan 19, 2022
@pull-request-quantifier-deprecated

This PR has 62 quantified lines of changes. In general, a change size of upto 200 lines is ideal for the best PR experience!


Quantification details

Label      : Small
Size       : +61 -1
Percentile : 24.8%

Total files changed: 4

Change summary by file extension:
.cs : +25 -0
.ps1 : +36 -1

Change counts above are quantified counts, based on the PullRequestQuantifier customizations.

Why proper sizing of changes matters

Optimal pull request sizes drive a better predictable PR flow as they strike a
balance between between PR complexity and PR review overhead. PRs within the
optimal size (typical small, or medium sized PRs) mean:

  • Fast and predictable releases to production:
    • Optimal size changes are more likely to be reviewed faster with fewer
      iterations.
    • Similarity in low PR complexity drives similar review times.
  • Review quality is likely higher as complexity is lower:
    • Bugs are more likely to be detected.
    • Code inconsistencies are more likely to be detetcted.
  • Knowledge sharing is improved within the participants:
    • Small portions can be assimilated better.
  • Better engineering practices are exercised:
    • Solving big problems by dividing them in well contained, smaller problems.
    • Exercising separation of concerns within the code changes.

What can I do to optimize my changes

  • Use the PullRequestQuantifier to quantify your PR accurately
    • Create a context profile for your repo using the context generator
    • Exclude files that are not necessary to be reviewed or do not increase the review complexity. Example: Autogenerated code, docs, project IDE setting files, binaries, etc. Check out the Excluded section from your prquantifier.yaml context profile.
    • Understand your typical change complexity, drive towards the desired complexity by adjusting the label mapping in your prquantifier.yaml context profile.
    • Only use the labels that matter to you, see context specification to customize your prquantifier.yaml context profile.
  • Change your engineering behaviors
    • For PRs that fall outside of the desired spectrum, review the details and check if:
      • Your PR could be split in smaller, self-contained PRs instead
      • Your PR only solves one particular issue. (For example, don't refactor and code new features in the same PR).

How to interpret the change counts in git diff output

  • One line was added: +1 -0
  • One line was deleted: +0 -1
  • One line was modified: +1 -1 (git diff doesn't know about modified, it will
    interpret that line like one addition plus one deletion)
  • Change percentiles: Change characteristics (addition, deletion, modification)
    of this PR in relation to all other PRs within the repository.


Was this comment helpful? 👍  :ok_hand:  :thumbsdown: (Email)
Customize PullRequestQuantifier for this repository.

@iSazonov
Copy link
Collaborator

Adding the ability for users to access a ResolvedTarget property on file and folder items, which returns a string representation of a path, depending on the type of file/folder:

  • If the file/folder is not a symbolic link, ResolvedTarget will return a string referring to itself.
  • If the file/folder is a symbolic link that points to a file/folder that currently exists, ResolvedTarget will return a string referring to the file/folder that the symbolic link points to.
  • If the file/folder is a symbolic link that points to a file that does not exist, ResolvedTarget returns a string referring to the broken destination.

@iSazonov
Copy link
Collaborator

@hammy3502 Thanks for your contribution! Please open doc issue.

@hammy275
Copy link
Contributor Author

@iSazonov The docs issue has been opened!

@iSazonov iSazonov removed the Documentation Needed in this repo Documentation is needed in this repo label Jan 21, 2022
@iSazonov iSazonov merged commit 3eca7c0 into PowerShell:master Jan 21, 2022
@iSazonov
Copy link
Collaborator

@hammy3502 Thanks for your contribution!

@ghost
Copy link

ghost commented Feb 24, 2022

🎉v7.3.0-preview.2 has been released which incorporates this pull request.:tada:

Handy links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log Committee-Reviewed PS-Committee has reviewed this and made a decision Small
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants