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

[API Implementation]: DirectoryInfo.CopyTo / Directory.Copy #62375

Closed
wants to merge 32 commits into from

Conversation

deeprobin
Copy link
Contributor

@deeprobin deeprobin commented Dec 3, 2021

Proposal implementation of #60903 (closes #60903)

Current state of implementation

  • Implementation
  • Ref Assembly
  • Documentation comments
  • Test Cases

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Dec 3, 2021
@ghost
Copy link

ghost commented Dec 3, 2021

Tagging subscribers to this area: @dotnet/area-system-io
See info in area-owners.md if you want to be subscribed.

Issue Details

See #60903

Current state of implementation

  • Implementation
  • Ref Assembly
  • Documentation comments
  • Test Cases
Author: deeprobin
Assignees: -
Labels:

area-System.IO

Milestone: -

@deeprobin deeprobin changed the title API proposal implementation: DirectoryInfo.Copy / Directory.Copy API proposal implementation: DirectoryInfo.CopyTo / Directory.Copy Dec 12, 2021
@deeprobin
Copy link
Contributor Author

Oh conflicts - I'll fix this the next days

@Symbai
Copy link

Symbai commented Jan 12, 2022

Oh conflicts - I'll fix this the next days

Maybe first ping the right people again to make sure the implementation is correct or not?! Because as long as its marked as draft, I doubt anyone from the .NET team looks at it.

@deeprobin
Copy link
Contributor Author

Oh conflicts - I'll fix this the next days

Maybe first ping the right people again to make sure the implementation is correct or not?! Because as long as its marked as draft, I doubt anyone from the .NET team looks at it.

Yeah.
@bartonjs @adamsitnik @carlossanlop 😄

@deeprobin deeprobin changed the title API proposal implementation: DirectoryInfo.CopyTo / Directory.Copy [API Implementation]: DirectoryInfo.CopyTo / Directory.Copy Jan 20, 2022
@Symbai
Copy link

Symbai commented Jan 21, 2022

@bartonjs Could you please say something about the implementation? The longer nobody of the .NET team takes a look the higher the chance everyone forgot was has been discussed and probably nobody except me wants to watch the review video. @deeprobin From all the pings we did not even a single one has reacted. Maybe doing you changes and removing the DRAFT helps, so this one at least needs to get reviewed.

@deeprobin
Copy link
Contributor Author

deeprobin commented Jan 21, 2022

@Symbai

Maybe doing you changes and removing the DRAFT helps, so this one at least needs to get reviewed.

I'll look into it this afternoon (CET) and then mark the PR as "Ready for Review".

@deeprobin deeprobin marked this pull request as ready for review January 23, 2022 14:28
@deeprobin
Copy link
Contributor Author

@Symbai It took a little longer for me. I have now marked it as "Ready for Review".

It's quite possible that the tests are not passing. But I think that's not so bad (for now).

@iSazonov
Copy link
Contributor

Why not use SHFileOperationW P/Invoke on Windows?
Perhaps there is something like on Unix too (libc?). /cc @tmds

@Symbai
Copy link

Symbai commented Jan 26, 2022

Why not use SHFileOperationW P/Invoke on Windows? Perhaps there is something like on Unix too (libc?). /cc @tmds

If you would have watched the video where the API got approved you would see that this WinAPI wouldn't fit into how this API should be implemented.

@deeprobin
Copy link
Contributor Author

Due to health problems, I was in the hospital the last few days and could not continue working on this (and several other issues).

I hope that I still bring the tests to pass in the course of this week.


directoryEnumeration = Directory.EnumerateDirectories(sourcePath, "*", enumerationOptions);
}
catch (IOException)
Copy link
Member

Choose a reason for hiding this comment

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

There's probably more to catch than IOExceptions here, isn't it? e.g DirectoryNotFoundException, UnauthorizedAccessException (see the Exceptions section in https://docs.microsoft.com/en-us/dotnet/api/system.io.directory.enumeratedirectories?view=net-6.0.).
Or maybe we should catch all of them?

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 have now updated this (See #62375 (comment)). I'm not sure if I have the right behavior for the exceptions though.

Can you take a look if there is anything that needs to be narrowed down.

@ghost ghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels Mar 7, 2022
@danmoseley
Copy link
Member

@deeprobin it would be great to drain some of your several open PR's. could you take a look at feedback here?

@deeprobin
Copy link
Contributor Author

@deeprobin it would be great to drain some of your several open PR's. could you take a look at feedback here?

As I wrote above, I will have a look at it the days. Currently I am still busy with a few changes to my nuint/nint Intrinsics overloads PR. But I think that I still manage to look at this PR this week.

The SafeFileHandle PR is completely finished from the implementation in my opinion. I have also requested a review from you there.
I think we can merge that first as soon as at least Jozkee and you have approved.

deeprobin and others added 6 commits March 10, 2022 21:18
Co-Authored-By: David Cantú <16040868+Jozkee@users.noreply.github.com>
Co-Authored-By: David Cantú <16040868+Jozkee@users.noreply.github.com>
src/libraries/System.IO.FileSystem/tests/Directory/Copy.cs Outdated Show resolved Hide resolved
src/libraries/System.IO.FileSystem/tests/Directory/Copy.cs Outdated Show resolved Hide resolved

// False because we only want to copy top level files (= non-recursive)
Assert.False(File.Exists(destThirdLevelFilePath));
}
Copy link
Member

Choose a reason for hiding this comment

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

You need to add tests for read and write errors, and for the simpler Directory.Copy overload.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my last commit, I added these. However, the two tests that check for it will fail.

I don't know exactly why but I guess it's still due to the problem that I don't know exactly how to clearly distinguish the read and write failures....

Maybe you can find another approach.

Feel free to cancel the CI, I'm sure it won't pass.

@ghost ghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Mar 14, 2022
@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Mar 15, 2022
Co-Authored-By: Tom Deseyn <tom.deseyn@gmail.com>
Co-Authored-By: David Cantú <16040868+jozkee@users.noreply.github.com>
@@ -10246,6 +10246,8 @@ public sealed partial class BufferedStream : System.IO.Stream
}
public static partial class Directory
{
public static bool Copy(string sourcePath, string destinationPath, bool recursive) { throw null; }
Copy link
Member

Choose a reason for hiding this comment

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

@Jozkee @adamsitnik @bartonjs @danmoseley @stephentoub this API fails in two different ways: by returning false, or by throwing IOException.

Can the user act upon this returing false in some meaningful way?
The false hides more information which would be conveyed in an IOException, like what path failed to read and why.
Splitting the error cases also makes the implementation more complex.

Can we change the signature to void and always throw IOException?

Copy link

Choose a reason for hiding this comment

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

@tmds: The API review video is still available, I recommend you watch it. The idea of returning false instead of throwing is/was that it should copy everything which can be copied and not immediately fail on the first exception. I believe this is a good decision, especially because when it fails even if we know what file/path has failed we still don't know what has been copied and what not. So the information you are looking for is only useful in a very limited way.

Copy link
Member

Choose a reason for hiding this comment

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

@Symbai it is an attempt to provide a best-effort copy where the user has no idea what has been copied and why the copy failed. That means it is hard to handle the false case.

I think it would be better to let the user roll their own best-effort copy and nail the semantics as they want them.

Most users for this API won't be looking for a best-effort copy, so this API forces them to deal with a false path they don't want.

Copy link

Choose a reason for hiding this comment

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

Well it has been discussed in API review and this is how it got approved and so it should get implemented. As for the pro and cons and why (arguments) please watch the API review video. There were also example situations discussed where returning false makes more sense than throwing. Also please don't speak for "Most users", as I for once don't agree.

Copy link
Member

Choose a reason for hiding this comment

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

@Symbai I watched the API review. I think the bool-return got added under the false presumption it was needed to know everything was copied.
Also in the review it gets mentioned there shouldn't be a ton of options, and if you want more specific behavior, you can do it enumerate yourself.
This bool return value represents the option 'SkipReadErrors' which every user of this API is now forced to handle as a specific case.

Copy link
Member

@stephentoub stephentoub Mar 28, 2022

Choose a reason for hiding this comment

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

If it returns false then now I have to do something more complicated

Do what? How do you know what went wrong and what to do differently next time / how to fix it so it doesn't happen again?

With no retry policy/error handler callback/etc, the method feels, to me, too trivial to be worth adding if it throws on the first failure (except for a few degenerate cases, like "your destination is an illegal path").

I agree with that. I also think it's not worth adding if it only does some of what you asked it to do and happily returns false with no additional information. If we want to throw an exception after it's completed copying whatever it can, that's fine; the API review discussed either throwing the first exception or the last exception or an aggregate... any of those seems better than returning false (though with an aggregate I'd worry about memory impact if lots of things in the copy failed).

Copy link
Member

Choose a reason for hiding this comment

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

Could we have a policy so we can satisfy several behaviors, including return false on errors and throw?
Something like:

public enum DirectoryCopyErrorPolicy
{
    Warn, // Best effort to copy, but return false if something failed.
    Throw, // throws an aggregate exception.
    ThrowFirst, // throws the first exception it gets.
}

I don't remember if we discussed this in API review.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe the issue should go back to API review? And we should close this PR for now?

Copy link

Choose a reason for hiding this comment

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

Or it should get implemented on how it was reviewed and improvements/changes are tracked in a separate issue. Wouldn't even be the first time.

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 think this should get back to APi review.

@@ -14,6 +18,58 @@ internal static void VerifyValidPath(string path, string argName)
}
}

internal static bool Copy(string sourcePath, string destinationPath, bool recursive,
Copy link
Member

Choose a reason for hiding this comment

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

nit: rename this method to CopyDirectory, and add full int the argument names to indicate the caller must provide the method with full paths.

@Jozkee
Copy link
Member

Jozkee commented Apr 15, 2022

Closing based on extraofficial API suggestions. Will bring the discussion back to the issue (#60903).
We can re-open this PR after we reach consensus there.

@Jozkee Jozkee closed this Apr 15, 2022
@ghost ghost locked as resolved and limited conversation to collaborators May 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.IO community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[API Proposal]: DirectoryInfo.Copy / Directory.Copy
9 participants