From e217f938d291854caaca4e5b81bbeb27c3e985ba Mon Sep 17 00:00:00 2001 From: Nathan Zimmerberg <39104088+nhz2@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:18:02 -0400 Subject: [PATCH] Make `rename` public (#55652) Fixes #41584. Follow up of #55503 I think `rename` is a very useful low-level file system operation. Many other programming languages have this function, so it is useful when porting IO code to Julia. One use case is to improve the Zarr.jl package to be more compatible with zarr-python. https://github.com/zarr-developers/zarr-python/blob/0b5483a7958e2ae5512a14eb424a84b2a75dd727/src/zarr/v2/storage.py#L994 uses the `os.replace` function. It would be nice to be able to directly use `Base.rename` as a replacement for `os.replace` to ensure compatibility. Another use case is writing a safe zip file extractor in pure Julia. https://github.com/madler/sunzip/blob/34107fa9e2a2e36e7e72725dc4c58c9ad6179898/sunzip.c#L365 uses the `rename` function to do this in C. Lastly in https://github.com/medyan-dev/MEDYANSimRunner.jl/blob/67d5b42cc599670486d5d640260a95e951091f7a/src/file-saving.jl#L83 I am using `ccall(:jl_fs_rename` to save files, because I have large numbers of Julia processes creating and reading these files at the same time on a distributed file system on a cluster, so I don't want data to become corrupted if one of the nodes crashes (which happens fairly regularly). However `jl_fs_rename` is not public, and might break in a future release. This PR also adds a note to `mv` comparing it to the `mv` command, similar to the note on the `cp` function. --- base/file.jl | 17 ++++++++++++++++- base/public.jl | 3 +++ doc/src/base/file.md | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/base/file.jl b/base/file.jl index d45f34fb55dc6..567783c4b1e5b 100644 --- a/base/file.jl +++ b/base/file.jl @@ -385,7 +385,7 @@ of the file or directory `src` refers to. Return `dst`. !!! note - The `cp` function is different from the `cp` command. The `cp` function always operates on + The `cp` function is different from the `cp` Unix command. The `cp` function always operates on the assumption that `dst` is a file, while the command does different things depending on whether `dst` is a directory or a file. Using `force=true` when `dst` is a directory will result in loss of all the contents present @@ -438,6 +438,16 @@ julia> mv("hello.txt", "goodbye.txt", force=true) julia> rm("goodbye.txt"); ``` + +!!! note + The `mv` function is different from the `mv` Unix command. The `mv` function by + default will error if `dst` exists, while the command will delete + an existing `dst` file by default. + Also the `mv` function always operates on + the assumption that `dst` is a file, while the command does different things depending + on whether `dst` is a directory or a file. + Using `force=true` when `dst` is a directory will result in loss of all the contents present + in the `dst` directory, and `dst` will become a file that has the contents of `src` instead. """ function mv(src::AbstractString, dst::AbstractString; force::Bool=false) if force @@ -1192,6 +1202,8 @@ If a path contains a "\\0" throw an `ArgumentError`. On other failures throw an `IOError`. Return `newpath`. +This is a lower level filesystem operation used to implement [`mv`](@ref). + OS-specific restrictions may apply when `oldpath` and `newpath` are in different directories. Currently there are a few differences in behavior on Windows which may be resolved in a future release. @@ -1202,6 +1214,9 @@ Specifically, currently on Windows: 4. `rename` may remove `oldpath` if it is a hardlink to `newpath`. See also: [`mv`](@ref). + +!!! compat "Julia 1.12" + This method was made public in Julia 1.12. """ function rename(oldpath::AbstractString, newpath::AbstractString) err = ccall(:jl_fs_rename, Int32, (Cstring, Cstring), oldpath, newpath) diff --git a/base/public.jl b/base/public.jl index 862aff48da63e..803766a0cec1b 100644 --- a/base/public.jl +++ b/base/public.jl @@ -110,6 +110,9 @@ public reseteof, link_pipe!, +# filesystem operations + rename, + # misc notnothing, runtests, diff --git a/doc/src/base/file.md b/doc/src/base/file.md index 22799f882bb26..300738a39322d 100644 --- a/doc/src/base/file.md +++ b/doc/src/base/file.md @@ -29,6 +29,7 @@ Base.Filesystem.operm Base.Filesystem.cp Base.download Base.Filesystem.mv +Base.Filesystem.rename Base.Filesystem.rm Base.Filesystem.touch Base.Filesystem.tempname