diff --git a/src/Artifacts.jl b/src/Artifacts.jl index ae47811e06..9f236ddb9d 100644 --- a/src/Artifacts.jl +++ b/src/Artifacts.jl @@ -65,20 +65,42 @@ Either rename the directory at `temp_dir` to `new_path` and set it to read-only or if `new_path` artifact already exists try to do nothing. """ function _mv_temp_artifact_dir(temp_dir::String, new_path::String)::Nothing - if !isdir(new_path) + # Sometimes a rename can fail because the temp_dir is locked by + # anti-virus software scanning the new files. + # In this case we want to sleep and try again. + # I am using the list of error codes to retry from: + # https://github.com/isaacs/node-graceful-fs/blob/234379906b7d2f4c9cfeb412d2516f42b0fb4953/polyfills.js#L87 + # Retry for up to about 60 seconds by retrying 20 times with exponential backoff. + retry = 0 + max_num_retries = 20 # maybe this should be configurable? + sleep_amount = 0.01 # seconds + max_sleep_amount = 5.0 # seconds + while true + isdir(new_path) && return # This next step is like # `mv(temp_dir, new_path)`. # However, `mv` defaults to `cp` if `rename` returns an error. # `cp` is not atomic, so avoid the potential of calling it. err = ccall(:jl_fs_rename, Int32, (Cstring, Cstring), temp_dir, new_path) - # Ignore rename error, but ensure `new_path` exists. - if !isdir(new_path) - error("$(repr(new_path)) could not be made") + if err ≥ 0 + # rename worked + chmod(new_path, filemode(dirname(new_path))) + set_readonly(new_path) + return + else + # Ignore rename error if `new_path` exists. + isdir(new_path) && return + if retry < max_num_retries && err ∈ (Base.UV_EACCES, Base.UV_EPERM, Base.UV_EBUSY) + sleep(sleep_amount) + sleep_amount = min(sleep_amount*2.0, max_sleep_amount) + retry += 1 + else + Base.uv_error("rename of $(repr(temp_dir)) to $(repr(new_path))", err) + end end chmod(new_path, filemode(dirname(new_path))) set_readonly(new_path) end - nothing end """ @@ -485,7 +507,7 @@ function with_show_download_info(f, io, name, quiet_download) if !quiet_download fancyprint && print(io, "\033[1A") # move cursor up one line fancyprint && print(io, "\033[2K") # clear line - if success + if success fancyprint && printpkgstyle(io, :Downloaded, "artifact: $name") else printpkgstyle(io, :Failure, "artifact: $name", color = :red)