-
Notifications
You must be signed in to change notification settings - Fork 51
Add replaceFile #200
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
base: master
Are you sure you want to change the base?
Add replaceFile #200
Conversation
d74c63b
to
9c9dc0e
Compare
System/Directory/OsPath.hs
Outdated
@@ -709,6 +710,30 @@ renamePath opath npath = | |||
(`ioeAddLocation` "renamePath") `modifyIOError` do | |||
renamePathInternal opath npath | |||
|
|||
-- | 'replaceFile' replaces one file with another file. The replacement file |
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 would be nice to elaborate explicitly how replaceFile
is different from renameFile
.
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 more description
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 documentation would help me much more if you add something like: "In constrast to renameFile
, replaceFile
... (is atomic?) You should use this when ... For example, consider this program ..."
In other words, the current explanation raises these questions with me:
- What do
renamePath
andReplaceFileW
do? (Perhaps this is just meant for people who are familiar with those functions and I should just ignore that sentence.) - What can go wrong if I use
renameFile
? Why is it important that it is atomic?
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.
On Windows
now renameFile
is MoveFileEx
and replaceFile
is ReplaceFileW
Atomic Operation in ReplaceFile:
- Creates a temporary backup of the original file (backup)
- Moves the new file to the original file's location
- Deletes the backup
On failure at step 2:
- Original file remains in backup
- New file stays in its original location
System preserves both versions!
For Comparison: MoveFileEx Behavior:
- Deletes the target file
- Moves the new file to target location
On failure at step 2:
- Target file is already deleted
- New file remains in its original location
Data is lost!
@@ -52,6 +52,7 @@ module System.Directory.OsPath | |||
, copyFile | |||
, copyFileWithMetadata | |||
, getFileSize | |||
, replaceFile |
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 convention is to provide the same set of functions both from System.Directory
and from System.Directory.OsPath
.
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
22cf56c
to
cb53340
Compare
|
As an outsider, it seems that |
I think it's merged and released now, in |
@Rufflewind Blocking the target name:
Access rights violation:
Recovery in case of failure
|
Is there any reason to ever use If we are going to have two functions it should be very clear from the documentation what the differences are and when you should use one over the other. You described (part of?) it in this comment, but that is not really reflected in the documentation. |
AFAIU from reading StackOverflow on Windows:
@zlonast could you confirm that my understanding is correct? What I don't know is how to achieve the semantics of Windows |
I think these are different functions, as a result they produce different attributes. Do you think it's normal for a general package to have some useless features for a particular platform? If you think it's not, let me know.
Yes, I think you're right, I'll fix it.
Yes
As I understand it, it doesn't make sense. From what I understand, I need |
@zlonast I don't quite follow all the details, but if the goal is to implement something in |
To make the tests pass, try updating the Win32 version number in .github/workflows/build.yml: directory/.github/workflows/build.yml Lines 25 to 27 in 6442a3c
|
-- | ||
-- The operation on Windows may fail with: | ||
-- | ||
-- ERROR_FILE_NOT_FOUND 2 (0x2) |
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.
To my understanding, the Haskell Win32
library does not expose the underlying Win32 API error code in the IOException
object, so the information here isn't really usable to users. It should really be rephrased as IOErrorType
s instead, and preferably merged with the Unix section if possible to reduce the platform-specific content for users. It's probably not worth documenting every single error case either, just the most commonly encountered ones.
@@ -85,6 +85,9 @@ removePathInternal False = Posix.removeLink . getOsString | |||
renamePathInternal :: OsPath -> OsPath -> IO () | |||
renamePathInternal (OsString p1) (OsString p2) = Posix.rename p1 p2 | |||
|
|||
replaceFileInternal :: OsPath -> OsPath -> Maybe OsPath -> IO () | |||
replaceFileInternal (OsString p1) (OsString p2) _ = Posix.rename p1 p2 |
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.
replaceFileInternal = renamePathInternal
haskell/cabal#10938
haskell/win32#240