Repository: JuliaLang/julia
File: base/file.jl (Julia)

Code before:
    if may_need_gc
        # this is only usually required on Sys.iswindows(), but may as well do it everywhere
        GC.gc(true)
    end
    @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(true)
    nothing
end

# deprecated internal function used by some packages
temp_cleanup_purge(; force=false) = force ? temp_cleanup_purge_all() : @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(false)

function temp_cleanup_postprocess(cleanup_dirs)
    if !isempty(cleanup_dirs)
        rmcmd = """
        eof(stdin)
        for path in eachline(stdin)
            try
                rm(path, force=true, recursive=true)
            catch ex
                @warn "Failed to clean up temporary path \$(repr(path))\n\$ex" _group=:file
            end
        end
        """
        cmd = Cmd(Base.cmd_gen(((Base.julia_cmd(),), ("--startup-file=no",), ("-e",), (rmcmd,))); ignorestatus = true, detach = true)
        pw = Base.PipeEndpoint()
        rd, wr = Base.link_pipe(true, true)
        try
            Base.open_pipe!(pw, wr)
        catch
            Base.close_pipe_sync(wr)
            rethrow()
        end
        run(cmd, rd, devnull, stderr; wait=false)
        join(pw, cleanup_dirs, "\n")
        Base.dup(wr) # intentionally leak a reference, until the process exits
        close(pw)
    end
end

function temp_cleanup_atexit()
    temp_cleanup_purge_all()
    temp_cleanup_postprocess(keys(TEMP_CLEANUP))
end

function __postinit__()
    Base.atexit(temp_cleanup_atexit)
end

const temp_prefix = "jl_"

# Use `Libc.rand()` to generate random strings

Review comment (suggestion):
You're leaking rd handle here. Rather than fix this up though, I'd prefer switching to the fully managed API. You're right I forgot rawhandle didn't return an fd. The function I was looking for was `Base._fd`

Code after:
            return true
        end
    end
    if may_need_gc
        # this is only usually required on Sys.iswindows(), but may as well do it everywhere
        GC.gc(true)
    end
    @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(true)
    nothing
end

# deprecated internal function used by some packages
temp_cleanup_purge(; force=false) = force ? temp_cleanup_purge_all() : @lock TEMP_CLEANUP_LOCK temp_cleanup_purge_prelocked(false)

function temp_cleanup_postprocess(cleanup_dirs)
    if !isempty(cleanup_dirs)
        rmcmd = """
        cleanuplist = readlines(stdin) # This loop won't start running until stdin is closed, which is supposed to be sequenced after the process exits
        sleep(1) # Wait for the operating system to hopefully be ready, since the OS implementation is probably incorrect, given the history of buggy work-arounds like this that have existed for ages in dotNet and libuv
        for path in cleanuplist
            try
                rm(path, force=true, recursive=true)
            catch ex
                @warn "Failed to clean up temporary path \$(repr(path))\n\$ex" _group=:file
            end
        end
        """
        cmd = Cmd(Base.cmd_gen(((Base.julia_cmd(),), ("--startup-file=no",), ("-e",), (rmcmd,))); ignorestatus = true, detach = true)
        pw = Base.PipeEndpoint()
        run(cmd, pw, devnull, stderr; wait=false)
        join(pw, cleanup_dirs, "\n")
        Base.dup(Base._fd(pw)) # intentionally leak a reference, until the process exits
        close(pw)
    end
end

function temp_cleanup_atexit()
    temp_cleanup_purge_all()
    @lock TEMP_CLEANUP_LOCK temp_cleanup_postprocess(keys(TEMP_CLEANUP))
end

function __postinit__()
    Base.atexit(temp_cleanup_atexit)
end

const temp_prefix = "jl_"

# Use `Libc.rand()` to generate random strings
function _rand_filename(len = 10)
    slug = Base.StringVector(len)
    chars = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"