@@ -436,15 +436,50 @@ function write_env_usage(source_file::AbstractString, usage_filepath::AbstractSt
436
436
# Ensure that log dir exists
437
437
! ispath (logdir ()) && mkpath (logdir ())
438
438
439
- # Generate entire entry as a string first
440
- entry = sprint () do io
441
- TOML. print (io, Dict (source_file => [Dict (" time" => now ())]))
442
- end
443
-
444
- # Append entry to log file in one chunk
445
439
usage_file = joinpath (logdir (), usage_filepath)
446
- open (usage_file, append= true ) do io
447
- write (io, entry)
440
+ timestamp = now ()
441
+
442
+ # # Atomically write usage file
443
+ while true
444
+ # read existing usage file
445
+ usage = if isfile (usage_file)
446
+ TOML. parsefile (usage_file)
447
+ else
448
+ Dict {String, Any} ()
449
+ end
450
+
451
+ # record new usage
452
+ usage[source_file] = [Dict (" time" => timestamp)]
453
+
454
+ # keep only latest usage info
455
+ for k in keys (usage)
456
+ times = map (d -> Dates. DateTime (d[" time" ]), usage[k])
457
+ usage[k] = [Dict (" time" => maximum (times))]
458
+ end
459
+
460
+ # Write to a temp file in the same directory as the destination
461
+ temp_usage_file = tempname (logdir ())
462
+ open (temp_usage_file, " w" ) do io
463
+ TOML. print (io, usage, sorted= true )
464
+ end
465
+
466
+ # Move the temp file into place, replacing the original
467
+ mv (temp_usage_file, usage_file, force = true )
468
+
469
+ # Check that the new file has what we want in it
470
+ new_usage = if isfile (usage_file)
471
+ TOML. parsefile (usage_file)
472
+ else
473
+ Dict {String, Any} ()
474
+ end
475
+ if haskey (new_usage, source_file)
476
+ for e in new_usage[source_file]
477
+ if Dates. DateTime (e[" time" ]) >= timestamp
478
+ return
479
+ end
480
+ end
481
+ end
482
+ # If not, try again
448
483
end
449
484
end
450
485
0 commit comments