@@ -463,15 +463,50 @@ function write_env_usage(source_file::AbstractString, usage_filepath::AbstractSt
463
463
# Ensure that log dir exists
464
464
! ispath (logdir ()) && mkpath (logdir ())
465
465
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
472
466
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
475
510
end
476
511
end
477
512
0 commit comments