Path separator issue on Windows
JackDunnNZ opened this issue · 4 comments
If there are mixed path separators in the path on Windows, then it can sometimes cause the specified file to not be found. For example, using the example in the test folder
using RelocatableFolders
PATH = @path "path"
FILE = joinpath("path", "subfolder/other.jl") # works
FILE = joinpath(PATH, "subfolder/other.jl") # doesn't find other.jl
FILE = joinpath(PATH, "subfolder\\other.jl") # works
FILE = joinpath(PATH, "subfolder", "other.jl") # works
The cause is that the paths may not compare equal at this line due to differences in the path separators used in each path. An easy fix is to instead compare normpath(path) == normpath(fullpath)
, but not sure if that's the best solution
Thanks for reporting this. I'm not able to reproduce the issue with the given example at the moment. By "works" and "doesn't find other.jl" do you mean that isfile(FILE)
is returning a false
for the second example, or that you're getting an error from it?
If you're able to make that example more reproducible that would be great. Could we also get versioninfo()
and ] st RelocatableFolders
output thanks? The output of dump(PATH)
may be helpful in diagnosing this as well.
Thanks for the response, and whoops, I totally messed up the example and left off the @path
in each call to FILE
, sorry about that. This should be fully reproducible from a fresh julia depot:
using RelocatableFolders
cd(joinpath(dirname(pathof(RelocatableFolders)), "../test"))
PATH = @path "path"
dump(PATH)
FILE = @path joinpath("path", "subfolder/other.jl")
dump(FILE)
FILE = @path joinpath(PATH, "subfolder/other.jl") # this one doesn't work, `FILE.files` is empty
dump(FILE)
FILE = @path joinpath(PATH, "subfolder\\other.jl")
dump(FILE)
FILE = @path joinpath(PATH, "subfolder", "other.jl")
dump(FILE)
Output from my system:
julia> versioninfo()
Julia Version 1.6.3
Commit ae8452a9e0 (2021-09-23 17:34 UTC)
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: AMD Ryzen Threadripper 2970WX 24-Core Processor
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.1 (ORCJIT, znver1)
(@v1.6) pkg> add RelocatableFolders
Installing known registries into `C:\Users\iai\.julia`
Cloning registry from "https://github.com/JuliaRegistries/General.git"
Added registry `General` to `C:\Users\iai\.julia\registries\General`
Resolving package versions...
Installed Scratch ──────────── v1.1.0
Installed RelocatableFolders ─ v0.1.2
Updating `C:\Users\iai\.julia\environments\v1.6\Project.toml`
[05181044] + RelocatableFolders v0.1.2
Updating `C:\Users\iai\.julia\environments\v1.6\Manifest.toml`
[05181044] + RelocatableFolders v0.1.2
[6c6a2e73] + Scratch v1.1.0
[ade2ca70] + Dates
[de0858da] + Printf
[ea8e919c] + SHA
[4ec0a83e] + Unicode
Precompiling project...
2 dependencies successfully precompiled in 5 seconds
julia> using RelocatableFolders
julia> cd(joinpath(dirname(pathof(RelocatableFolders)), "../test"))
julia> PATH = @path "path"
"C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path"
julia> dump(PATH)
RelocatableFolders.Path
is_dir: Bool true
mod: Module Main
path: String "C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path"
hash: String "d306ff6859f4ea072957d2b4ef79899035feebb1"
files: Dict{String, Vector{UInt8}}
slots: Array{UInt8}((16,)) UInt8[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00]
keys: Array{String}((16,))
1: #undef
2: #undef
3: #undef
4: String "text.md"
5: #undef
...
12: String "file.jl"
13: String "subfolder\\other.jl"
14: #undef
15: #undef
16: #undef
vals: Array{Vector{UInt8}}((16,))
1: #undef
2: #undef
3: #undef
4: Array{UInt8}((7,)) UInt8[0x74, 0x65, 0x78, 0x74, 0x2e, 0x6d, 0x64]
5: #undef
...
12: Array{UInt8}((9,)) UInt8[0x23, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x6a, 0x6c]
13: Array{UInt8}((10,)) UInt8[0x23, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x6a, 0x6c]
14: #undef
15: #undef
16: #undef
ndel: Int64 0
count: Int64 3
age: UInt64 0x0000000000000003
idxfloor: Int64 1
maxprobe: Int64 0
julia> FILE = @path joinpath("path", "subfolder/other.jl")
"C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path\\subfolder\\other.jl"
julia> dump(FILE)
RelocatableFolders.Path
is_dir: Bool false
mod: Module Main
path: String "C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path\\subfolder"
hash: String "f7864905002a58658723784aac886712ef7ce302"
files: Dict{String, Vector{UInt8}}
slots: Array{UInt8}((16,)) UInt8[0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
keys: Array{String}((16,))
1: #undef
2: String "other.jl"
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
vals: Array{Vector{UInt8}}((16,))
1: #undef
2: Array{UInt8}((10,)) UInt8[0x23, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x6a, 0x6c]
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
ndel: Int64 0
count: Int64 1
age: UInt64 0x0000000000000001
idxfloor: Int64 1
maxprobe: Int64 0
julia> FILE = @path joinpath(PATH, "subfolder/other.jl")
Error showing value of type RelocatableFolders.Path:
ERROR: ArgumentError: collection must be non-empty
Stacktrace:
[1] first
@ .\abstractarray.jl:387 [inlined]
[2] getroot(p::RelocatableFolders.Path, root::String) (repeats 2 times)
@ RelocatableFolders C:\Users\iai\.julia\packages\RelocatableFolders\2eEye\src\RelocatableFolders.jl:90
[3] show
@ C:\Users\iai\.julia\packages\RelocatableFolders\2eEye\src\RelocatableFolders.jl:69 [inlined]
[4] show(io::IOContext{Base.TTY}, #unused#::MIME{Symbol("text/plain")}, x::RelocatableFolders.Path)
@ Base.Multimedia .\multimedia.jl:47
[5] (::REPL.var"#38#39"{REPL.REPLDisplay{REPL.LineEditREPL}, MIME{Symbol("text/plain")}, Base.RefValue{Any}})(io::Any)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:220
[6] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:462
[7] display(d::REPL.REPLDisplay, mime::MIME{Symbol("text/plain")}, x::Any)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:213
[8] display(d::REPL.REPLDisplay, x::Any)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:225
[9] display(x::Any)
@ Base.Multimedia .\multimedia.jl:328
[10] #invokelatest#2
@ .\essentials.jl:708 [inlined]
[11] invokelatest
@ .\essentials.jl:706 [inlined]
[12] print_response(errio::IO, response::Any, show_value::Bool, have_color::Bool, specialdisplay::Union{Nothing, AbstractDisplay})
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:247
[13] (::REPL.var"#40#41"{REPL.LineEditREPL, Pair{Any, Bool}, Bool, Bool})(io::Any)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:231
[14] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:462
[15] print_response(repl::REPL.AbstractREPL, response::Any, show_value::Bool, have_color::Bool)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:229
[16] (::REPL.var"#do_respond#61"{Bool, Bool, REPL.var"#72#82"{REPL.LineEditREPL, REPL.REPLHistoryProvider}, REPL.LineEditREPL, REPL.LineEdit.Prompt})(s::REPL.LineEdit.MIState, buf::Any, ok::Bool)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:798
[17] #invokelatest#2
@ .\essentials.jl:708 [inlined]
[18] invokelatest
@ .\essentials.jl:706 [inlined]
[19] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
@ REPL.LineEdit C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\LineEdit.jl:2441
[20] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:1126
[21] (::REPL.var"#44#49"{REPL.LineEditREPL, REPL.REPLBackendRef})()
@ REPL .\task.jl:411
julia> dump(FILE)
RelocatableFolders.Path
is_dir: Bool false
mod: Module Main
path: String "C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path\\subfolder"
hash: String "da39a3ee5e6b4b0d3255bfef95601890afd80709"
files: Dict{String, Vector{UInt8}}
slots: Array{UInt8}((16,)) UInt8[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
keys: Array{String}((16,))
1: #undef
2: #undef
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
vals: Array{Vector{UInt8}}((16,))
1: #undef
2: #undef
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
ndel: Int64 0
count: Int64 0
age: UInt64 0x0000000000000000
idxfloor: Int64 1
maxprobe: Int64 0
julia> FILE = @path joinpath(PATH, "subfolder\\other.jl")
"C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path\\subfolder\\other.jl"
julia> dump(FILE)
RelocatableFolders.Path
is_dir: Bool false
mod: Module Main
path: String "C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path\\subfolder"
hash: String "f7864905002a58658723784aac886712ef7ce302"
files: Dict{String, Vector{UInt8}}
slots: Array{UInt8}((16,)) UInt8[0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
keys: Array{String}((16,))
1: #undef
2: String "other.jl"
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
vals: Array{Vector{UInt8}}((16,))
1: #undef
2: Array{UInt8}((10,)) UInt8[0x23, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x6a, 0x6c]
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
ndel: Int64 0
count: Int64 1
age: UInt64 0x0000000000000001
idxfloor: Int64 1
maxprobe: Int64 0
julia> FILE = @path joinpath(PATH, "subfolder", "other.jl")
"C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path\\subfolder\\other.jl"
julia> dump(FILE)
RelocatableFolders.Path
is_dir: Bool false
mod: Module Main
path: String "C:\\Users\\iai\\.julia\\packages\\RelocatableFolders\\2eEye\\test\\path\\subfolder"
hash: String "f7864905002a58658723784aac886712ef7ce302"
files: Dict{String, Vector{UInt8}}
slots: Array{UInt8}((16,)) UInt8[0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
keys: Array{String}((16,))
1: #undef
2: String "other.jl"
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
vals: Array{Vector{UInt8}}((16,))
1: #undef
2: Array{UInt8}((10,)) UInt8[0x23, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x6a, 0x6c]
3: #undef
4: #undef
5: #undef
...
12: #undef
13: #undef
14: #undef
15: #undef
16: #undef
ndel: Int64 0
count: Int64 1
age: UInt64 0x0000000000000001
idxfloor: Int64 1
maxprobe: Int64 0
Cool, that did the trick. A normpath
is probably needed, I think just doing it at the start of that function is probably best, i.e. https://github.com/JuliaPackaging/RelocatableFolders.jl/blob/main/src/RelocatableFolders.jl#L48 path = normpath(path)
just to ensure it's normalised throughout the function. Would you like to PR that fix?
Thanks, done!