Skip to content

Commit c2a28ee

Browse files
committed
Merge pull request #11172 from peter1000/adds_kw_remove_destination_to__mv
Adds kw `remove_destination` to `mv` function #11145
2 parents c790369 + 43eb785 commit c2a28ee

File tree

7 files changed

+315
-88
lines changed

7 files changed

+315
-88
lines changed

NEWS.md

+3
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ Library improvements
260260

261261
* The `cp` function now accepts keyword arguments `remove_destination` and `follow_symlinks` ([#10888]).
262262

263+
* The `mv` function now accepts keyword argument `remove_destination` ([#11145]).
264+
263265
* Other improvements
264266

265267
* You can now tab-complete Emoji characters via their [short names](http://www.emoji-cheat-sheet.com/), using `\:name:<tab>` ([#10709]).
@@ -1405,3 +1407,4 @@ Too numerous to mention.
14051407
[#10893]: https://github.com/JuliaLang/julia/issues/10893
14061408
[#10914]: https://github.com/JuliaLang/julia/issues/10914
14071409
[#10994]: https://github.com/JuliaLang/julia/issues/10994
1410+
[#11145]: https://github.com/JuliaLang/julia/issues/11145

base/file.jl

+25-14
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,32 @@ end
7171

7272

7373
# The following use Unix command line facilites
74-
75-
function cptree(src::AbstractString, dst::AbstractString; remove_destination::Bool=false,
76-
follow_symlinks::Bool=false)
77-
isdir(src) || throw(ArgumentError("'$src' is not a directory. Use `cp(src, dst)`"))
74+
function checkfor_mv_cp_cptree(src::AbstractString, dst::AbstractString, txt::AbstractString;
75+
remove_destination::Bool=false)
7876
if ispath(dst)
7977
if remove_destination
78+
# Check for issue when: (src == dst) or when one is a link to the other
79+
# https://github.com/JuliaLang/julia/pull/11172#issuecomment-100391076
80+
if Base.samefile(src, dst)
81+
abs_src = islink(src) ? abspath(readlink(src)) : abspath(src)
82+
abs_dst = islink(dst) ? abspath(readlink(dst)) : abspath(dst)
83+
throw(ArgumentError(string("'src' and 'dst' refer to the same file/dir.",
84+
"This is not supported.\n ",
85+
"`src` refers to: $(abs_src)\n ",
86+
"`dst` refers to: $(abs_dst)\n")))
87+
end
8088
rm(dst; recursive=true)
8189
else
8290
throw(ArgumentError(string("'$dst' exists. `remove_destination=true` ",
83-
"is required to remove '$dst' before copying.")))
91+
"is required to remove '$dst' before $(txt).")))
8492
end
8593
end
94+
end
95+
96+
function cptree(src::AbstractString, dst::AbstractString; remove_destination::Bool=false,
97+
follow_symlinks::Bool=false)
98+
isdir(src) || throw(ArgumentError("'$src' is not a directory. Use `cp(src, dst)`"))
99+
checkfor_mv_cp_cptree(src, dst, "copying"; remove_destination=remove_destination)
86100
mkdir(dst)
87101
for name in readdir(src)
88102
srcname = joinpath(src, name)
@@ -99,14 +113,7 @@ end
99113

100114
function cp(src::AbstractString, dst::AbstractString; remove_destination::Bool=false,
101115
follow_symlinks::Bool=false)
102-
if ispath(dst)
103-
if remove_destination
104-
rm(dst; recursive=true)
105-
else
106-
throw(ArgumentError(string("'$dst' exists. `remove_destination=true` ",
107-
"is required to remove '$dst' before copying.")))
108-
end
109-
end
116+
checkfor_mv_cp_cptree(src, dst, "copying"; remove_destination=remove_destination)
110117
if !follow_symlinks && islink(src)
111118
symlink(readlink(src), dst)
112119
elseif isdir(src)
@@ -115,7 +122,11 @@ function cp(src::AbstractString, dst::AbstractString; remove_destination::Bool=f
115122
FS.sendfile(src, dst)
116123
end
117124
end
118-
mv(src::AbstractString, dst::AbstractString) = FS.rename(src, dst)
125+
126+
function mv(src::AbstractString, dst::AbstractString; remove_destination::Bool=false)
127+
checkfor_mv_cp_cptree(src, dst, "moving"; remove_destination=remove_destination)
128+
FS.rename(src, dst)
129+
end
119130

120131
function touch(path::AbstractString)
121132
f = FS.open(path,JL_O_WRONLY | JL_O_CREAT, 0o0666)

base/fs.jl

+3-7
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,11 @@ end
115115
# For move command
116116
function rename(src::AbstractString, dst::AbstractString)
117117
err = ccall(:jl_fs_rename, Int32, (Cstring, Cstring), src, dst)
118-
119118
# on error, default to cp && rm
120119
if err < 0
121-
# Note that those two functions already handle their errors.
122-
# first copy
123-
sendfile(src, dst)
124-
125-
# then rm
126-
unlink(src)
120+
# remove_destination: is already done in the mv function
121+
cp(src, dst; remove_destination=false, follow_symlinks=false)
122+
rm(src; recursive=true)
127123
end
128124
end
129125

base/stat.jl

+8-1
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,12 @@ filesize(path...) = stat(path...).size
115115
mtime(path...) = stat(path...).mtime
116116
ctime(path...) = stat(path...).ctime
117117

118+
# samefile can be used for files and directories: #11145#issuecomment-99511194
118119
samefile(a::StatStruct, b::StatStruct) = a.device==b.device && a.inode==b.inode
119-
samefile(a::AbstractString, b::AbstractString) = samefile(stat(a),stat(b))
120+
function samefile(a::AbstractString, b::AbstractString)
121+
if ispath(a) && ispath(b)
122+
samefile(stat(a),stat(b))
123+
else
124+
return false
125+
end
126+
end

doc/helpdb.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -5261,9 +5261,10 @@ Millisecond(v)
52615261
52625262
"),
52635263

5264-
("Base","mv","mv(src::AbstractString, dst::AbstractString)
5264+
("Base","mv","mv(src::AbstractString,dst::AbstractString; remove_destination::Bool=false)
52655265
5266-
Move a file from *src* to *dst*.
5266+
Move the file, link, or directory from *src* to *dest*.
5267+
\"remove_destination=true\" will first remove an existing `dst`.
52675268
52685269
"),
52695270

doc/stdlib/file.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,10 @@
126126
use or situations in which more options are need, please use a package that provides the
127127
desired functionality instead.
128128

129-
.. function:: mv(src::AbstractString,dst::AbstractString)
129+
.. function:: mv(src::AbstractString,dst::AbstractString; remove_destination::Bool=false)
130130

131-
Move a file from `src` to `dst`.
131+
Move the file, link, or directory from *src* to *dest*.
132+
\"remove_destination=true\" will first remove an existing `dst`.
132133

133134
.. function:: rm(path::AbstractString; recursive=false)
134135

0 commit comments

Comments
 (0)