Mktempdir() on AppVeyor on Windows

question

#1

I decided to try and get my code running on Windows… On Appveyor, the following code:

 mktempdir() do tmpdir
    cd(tmpdir)
    info("running tests in: $(pwd())")
    run_all_tests()
end

appears to fail at the end, with the error:

ERROR: LoadError: SystemError (with C:\Users\appveyor\AppData\Local\Temp\1\jl_59FC.tmp): rmdir: Permission denied
Stacktrace:
 [1] #systemerror#51 at .\error.jl:64 [inlined]
 [2] (::Base.#kw##systemerror)(::Array{Any,1}, ::Base.#systemerror, ::Symbol, ::Bool) at .\<missing>:0
 [3] #rm#7(::Bool, ::Bool, ::Function, ::String) at .\file.jl:159
 [4] (::Base.Filesystem.#kw##rm)(::Array{Any,1}, ::Base.Filesystem.#rm, ::String) at .\<missing>:0
 [5] mktempdir(::##1#2, ::String) at .\file.jl:388
 [6] mktempdir(::Function) at .\file.jl:384
 [7] include_from_node1(::String) at .\loading.jl:532
 [8] include(::String) at .\sysimg.jl:14
 [9] process_options(::Base.JLOptions) at .\client.jl:308
 [10] _start() at .\client.jl:374

which I presume is what happens when the mktempdir() block finishes. Is there some magic incantation which lets the test run with some basic deleting powers? Or have I configured something wrong?


#2

This is probably not an actual permissions issue. If you have permission to mktempdir() you should have permission to delete. While *nix file systems can de-link inodes with open handles, Windows has no mechanism to delete files in use, and doesn’t return any error more specific than “Permission denied” when failing to delete an open file.

I’m not sure of the best way to deal with this (workspace() might help), but you could clear tmp data from the driver script – Appveyor yml supports dos and powershell commands – and could likely get away with not doing anything; the test VMs should be reset upon completion.


#3

I think it was Tony who told me I should delete temp files created during testing, but doing it file by file would be painful. Perhaps my test should use the mktempdir block on *nix only…


#4

Most likely you have file handles still open to something you just created. So it’s not just the creation of the temp dir that needs a do-block, but also opening of any file handles to things you create within it.


#5

I think I’ve fixed this problem. On Unix, you can do this:

mktempdir() do tmpdir
        cd(tmpdir)
        run_all_tests()
end

But if you want this to run on Windows as well, you must do this:

mktempdir() do tmpdir
        olddir = pwd()
        cd(tmpdir)
        run_all_tests()
        cd(olddir)
end

If you’re in a directory, you can’t delete it. (It’s sort of obvious, although it’s easy to say that now!)

Unix lets you do this. But if you do, you can get into trouble:

julia> pwd()
"/private/tmp"

julia> mktempdir() do tmpdir
           cd(tmpdir)
           ....
       end

julia> pwd()
ERROR: getcwd: no such file or directory (ENOENT)
 in uv_error(::Symbol, ::Int32) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
 in pwd() at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
 in pwd() at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?

shell> cd /tmp
ERROR: getcwd: no such file or directory (ENOENT)
 in uv_error(::Symbol, ::Int32) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
 in pwd() at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
 in repl_cmd(::Cmd, ::Base.Terminals.TTYTerminal) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?
 in repl_cmd(::Cmd, ::Base.Terminals.TTYTerminal) at /Applications/Julia-0.5.app/Contents/Resources/julia/lib/julia/sys.dylib:?

shell> ls
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory

Julia to the rescue, though!

julia> cd("/tmp")
julia> readdir()
12-element Array{String,1}:
 ".DS_Store"
 "2794a5d9ca14d45de4fd32232844b4a5"
 "587495bd1c52b"
 "5877bd5dc6915"
 "5879d3cb47af2"
 "587e78c1cbfc4"
 "58806b685b1c2"
 "Atom Crashes"
 "com.apple.launchd.sV7M48F9gC"
 "com.apple.launchd.ztFinGyRSO"
 "hypotrochoid.png"
 "stellarium"

#6

cd has a do block form too, so you don’t have to save oldpwd manually.


#7

Ah, that’s good to know. Thanks!


#8

I wonder if it would make sense to have a mktempdir(; cd::Bool=false) keyword argument that takes care of this correctly with a single try/catch block and a single level of indentation.