@@ -463,15 +463,50 @@ function write_env_usage(source_file::AbstractString, usage_filepath::AbstractSt
463463 # Ensure that log dir exists
464464 ! ispath (logdir ()) && mkpath (logdir ())
465465
466- # Generate entire entry as a string first
467- entry = sprint () do io
468- TOML. print (io, Dict (source_file => [Dict (" time" => now ())]))
469- end
470-
471- # Append entry to log file in one chunk
472466 usage_file = joinpath (logdir (), usage_filepath)
473- open (usage_file, append= true ) do io
474- write (io, entry)
467+ timestamp = now ()
468+
469+ # # Atomically write usage file
470+ while true
471+ # read existing usage file
472+ usage = if isfile (usage_file)
473+ TOML. parsefile (usage_file)
474+ else
475+ Dict {String, Any} ()
476+ end
477+
478+ # record new usage
479+ usage[source_file] = [Dict (" time" => timestamp)]
480+
481+ # keep only latest usage info
482+ for k in keys (usage)
483+ times = map (d -> Dates. DateTime (d[" time" ]), usage[k])
484+ usage[k] = [Dict (" time" => maximum (times))]
485+ end
486+
487+ # Write to a temp file in the same directory as the destination
488+ temp_usage_file = tempname (logdir ())
489+ open (temp_usage_file, " w" ) do io
490+ TOML. print (io, usage, sorted= true )
491+ end
492+
493+ # Move the temp file into place, replacing the original
494+ mv (temp_usage_file, usage_file, force = true )
495+
496+ # Check that the new file has what we want in it
497+ new_usage = if isfile (usage_file)
498+ TOML. parsefile (usage_file)
499+ else
500+ Dict {String, Any} ()
501+ end
502+ if haskey (new_usage, source_file)
503+ for e in new_usage[source_file]
504+ if Dates. DateTime (e[" time" ]) >= timestamp
505+ return
506+ end
507+ end
508+ end
509+ # If not, try again
475510 end
476511end
477512
0 commit comments