Julia 1.11:
cd(mktempdir())
mkpath("uwe/")
Output: "uwe"
Julia 1.12-rc1:
cd(mktempdir())
mkpath("uwe/")
Output: "uwe/"
This difference causes my unit tests to fail.
Is this a bug, or just undefined behaviour?
This is on Ubuntu Linux.
If you care about your mental sanity, you should really not rely on the trailing path separator being there, you should always get rid of it before doing anything else with that path. See [Breaking] Make `basename` and `dirname` ignore a trailing path separator Β· Issue #43137 Β· JuliaLang/julia Β· GitHub as an example where the trailing separator causes different behaviour.
In principle, I agree. But I still do not know if I should report that as bug in the Julia repo.
That seems to be a deliberate change:
master β ctarn:mkpath
opened 12:34PM - 20 Jun 24 UTC
fix #54826
related performance test code:
```julia
using BenchmarkTools
us⦠ing Base: IOError
function checkmode(mode::Integer)
if !(0 <= mode <= 511)
throw(ArgumentError("Mode must be between 0 and 511 = 0o777"))
end
mode
end
function mkpath(path::AbstractString; mode::Integer = 0o777)
dir = dirname(path)
# stop recursion for `""`, `"/"`, or existed dir
(path == dir || isdir(path)) && return path
mkpath(dir, mode = checkmode(mode))
try
# cases like `mkpath("x/")` will cause an error if `isdir(path)` is skipped
# the error will not be rethrowed, but it may be slower, and thus we avoid it in advance
isdir(path) || mkdir(path, mode = mode)
catch err
# If there is a problem with making the directory, but the directory
# does in fact exist, then ignore the error. Else re-throw it.
if !isa(err, IOError) || !isdir(path)
rethrow()
end
end
return path
end
function mkpath_2(path::AbstractString; mode::Integer = 0o777)
dir = dirname(path)
# stop recursion for `""` and `"/"` or existed dir
(path == dir || isdir(path)) && return path
mkpath_2(dir, mode = checkmode(mode))
try
mkdir(path, mode = mode)
catch err
# If there is a problem with making the directory, but the directory
# does in fact exist, then ignore the error. Else re-throw it.
if !isa(err, IOError) || !isdir(path)
rethrow()
end
end
return path
end
versioninfo()
display(@benchmark begin rm("A", recursive=true, force=true); mkpath("A/B/C/D/") end)
display(@benchmark begin rm("A", recursive=true, force=true); mkpath_2("A/B/C/D/") end)
```
output:
```
Julia Version 1.10.4
Commit 48d4fd48430 (2024-06-04 10:41 UTC)
Build Info:
Official https://julialang.org/ release
Platform Info:
OS: macOS (x86_64-apple-darwin22.4.0)
CPU: 16 Γ Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-15.0.7 (ORCJIT, skylake)
Threads: 1 default, 0 interactive, 1 GC (on 16 virtual cores)
Environment:
JULIA_EDITOR = code
JULIA_NUM_THREADS =
BenchmarkTools.Trial: 8683 samples with 1 evaluation.
Range (min β¦ max): 473.972 ΞΌs β¦ 18.867 ms β GC (min β¦ max): 0.00% β¦ 0.00%
Time (median): 519.704 ΞΌs β GC (median): 0.00%
Time (mean Β± Ο): 571.261 ΞΌs Β± 378.851 ΞΌs β GC (mean Β± Ο): 0.00% Β± 0.00%
βββββ
ββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββ β
474 ΞΌs Histogram: frequency by time 961 ΞΌs <
Memory estimate: 5.98 KiB, allocs estimate: 65.
BenchmarkTools.Trial: 6531 samples with 1 evaluation.
Range (min β¦ max): 588.122 ΞΌs β¦ 17.449 ms β GC (min β¦ max): 0.00% β¦ 0.00%
Time (median): 660.071 ΞΌs β GC (median): 0.00%
Time (mean Β± Ο): 760.333 ΞΌs Β± 615.759 ΞΌs β GC (mean Β± Ο): 0.00% Β± 0.00%
βββββββ β
βββββββββββββββββ
β
β
βββββββββββββββββββββββββββββββββββββββ
β
ββ β
588 ΞΌs Histogram: log(frequency) by time 4.2 ms <
Memory estimate: 5.63 KiB, allocs estimate: 72.
```
The linked issue specifically talks about the case of directories ending with path separator. The handling of the trailing path separator is maddening.