|
16 | 16 | using System.Runtime.Versioning; |
17 | 17 | using System.Text; |
18 | 18 | using System.Text.Json; |
19 | | -using System.Text.Json.Serialization; |
20 | 19 | using System.Text.RegularExpressions; |
21 | 20 | using Microsoft.VisualStudio.Setup.Configuration; |
22 | 21 | using Microsoft.Win32; |
@@ -278,73 +277,120 @@ public static void LogWrite(string msg, params object[] args) |
278 | 277 |
|
279 | 278 | public static List<string> FilesAlternatesAutoCleanupDBSuffixes = new List<string>(); // The alternates db suffixes using by other context |
280 | 279 | private static List<string> _FilesAlternatesAutoCleanupDBFullPaths = new List<string>(); |
281 | | - public static string FilesAutoCleanupDBPath = string.Empty; |
282 | | - public static string FilesAutoCleanupDBSuffix = string.Empty; // Current auto-cleanup suffix for the database. |
| 280 | + public static string FilesAutoCleanupDBPath { get; set; } = string.Empty; |
| 281 | + public static string FilesAutoCleanupDBSuffix { get; set; } = string.Empty; // Current auto-cleanup suffix for the database. |
283 | 282 | internal static bool s_forceFilesCleanup = false; |
284 | 283 | internal static string s_overrideFilesAutoCleanupDBPath; |
285 | | - public static bool FilesAutoCleanupActive = false; |
286 | | - public static TimeSpan FilesAutoCleanupDelay = TimeSpan.Zero; |
| 284 | + |
| 285 | + public static bool FilesAutoCleanupActive { get; set; } |
| 286 | + public static TimeSpan FilesAutoCleanupDelay { get; set; } = TimeSpan.Zero; |
287 | 287 | public static HashSet<string> FilesToBeExplicitlyRemovedFromDB = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase); |
288 | 288 | public static HashSet<string> FilesAutoCleanupIgnoredEndings = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase); |
289 | 289 | private const string s_filesAutoCleanupDBPrefix = "sharpmakeautocleanupdb"; |
290 | | - private enum DBVersion { Version = 3 }; |
291 | 290 |
|
292 | 291 | private static JsonSerializerOptions GetCleanupDatabaseJsonSerializerOptions() |
293 | 292 | { |
294 | 293 | return new JsonSerializerOptions() |
295 | 294 | { |
296 | 295 | AllowTrailingCommas = true, |
297 | 296 | PropertyNamingPolicy = null, |
298 | | - WriteIndented = false, |
| 297 | + WriteIndented = true, |
299 | 298 | }; |
300 | 299 | } |
301 | 300 |
|
| 301 | + private class CleanupDatabaseContent |
| 302 | + { |
| 303 | + public enum DBVersions |
| 304 | + { |
| 305 | + BinaryFormatterVersion = 3, // Json in a binary formatter - Deprecated - Support will be removed in the first version released after dec 31th 2024 |
| 306 | + JsonVersion = 4, // New format - simple json |
| 307 | + CurrentVersion = JsonVersion |
| 308 | + }; |
| 309 | + |
| 310 | + public DBVersions DBVersion { get; set; } |
| 311 | + public object Data { get; set; } |
| 312 | + } |
| 313 | + |
302 | 314 | private static Dictionary<string, DateTime> ReadCleanupDatabase(string databaseFilename) |
303 | 315 | { |
304 | | - Dictionary<string, DateTime> dbFiles = null; |
305 | | - if (File.Exists(databaseFilename)) |
| 316 | + // DEPRECATED CODE - TO BE REMOVED AFTER DEC 31TH 2024 |
| 317 | + string oldDatabaseFormatFilename = Path.ChangeExtension(databaseFilename, ".bin"); |
| 318 | + if (File.Exists(oldDatabaseFormatFilename)) |
306 | 319 | { |
307 | 320 | try |
308 | 321 | { |
309 | 322 | // Read database - This is simply a simple binary file containing the list of file and a version number. |
310 | | - using (Stream readStream = new FileStream(databaseFilename, FileMode.Open, FileAccess.Read, FileShare.None)) |
| 323 | + using (Stream readStream = new FileStream(oldDatabaseFormatFilename, FileMode.Open, FileAccess.Read, FileShare.None)) |
311 | 324 | using (BinaryReader binReader = new BinaryReader(readStream)) |
312 | 325 | { |
313 | 326 | // Validate version number |
314 | 327 | int version = binReader.ReadInt32(); |
315 | | - if (version == (int)DBVersion.Version) |
| 328 | + if (version == (int)CleanupDatabaseContent.DBVersions.BinaryFormatterVersion) |
316 | 329 | { |
317 | 330 | // Read the list of files. |
318 | 331 | IFormatter formatter = new BinaryFormatter(); |
319 | 332 | string dbAsJson = binReader.ReadString(); |
320 | 333 |
|
321 | 334 | var tmpDbFiles = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, DateTime>>(dbAsJson, GetCleanupDatabaseJsonSerializerOptions()); |
322 | | - dbFiles = tmpDbFiles.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.InvariantCultureIgnoreCase); |
| 335 | + var dbFiles = tmpDbFiles.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.InvariantCultureIgnoreCase); |
| 336 | + |
| 337 | + // Converting to new format. |
| 338 | + WriteCleanupDatabase(databaseFilename, dbFiles); |
| 339 | + return dbFiles; |
323 | 340 | } |
324 | 341 | else |
325 | 342 | { |
326 | 343 | LogWrite("Warning: found cleanup database in incompatible format v{0}, skipped.", version); |
327 | 344 | } |
| 345 | + } |
| 346 | + } |
| 347 | + catch |
| 348 | + { |
| 349 | + // nothing to do. |
| 350 | + } |
| 351 | + finally |
| 352 | + { |
| 353 | + TryDeleteFile(oldDatabaseFormatFilename); |
| 354 | + } |
| 355 | + } |
| 356 | + // END DEPRECATED CODE |
| 357 | + |
| 358 | + if (File.Exists(databaseFilename)) |
| 359 | + { |
| 360 | + try |
| 361 | + { |
| 362 | + string jsonString = File.ReadAllText(databaseFilename); |
| 363 | + var versionedDB = System.Text.Json.JsonSerializer.Deserialize<CleanupDatabaseContent>(jsonString); |
| 364 | + if (versionedDB.DBVersion == CleanupDatabaseContent.DBVersions.JsonVersion) |
| 365 | + { |
| 366 | + // Deserialize the Database to a dictionary |
| 367 | + var tmpDbFiles = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, DateTime>>(versionedDB.Data.ToString(), GetCleanupDatabaseJsonSerializerOptions()); |
328 | 368 |
|
329 | | - readStream.Close(); |
| 369 | + // Convert the dictionary to a case insensitive dictionary |
| 370 | + var dbFiles = tmpDbFiles.ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.InvariantCultureIgnoreCase); |
| 371 | + |
| 372 | + return dbFiles; |
| 373 | + } |
| 374 | + else |
| 375 | + { |
| 376 | + LogWrite($"Cleanup database version {versionedDB.DBVersion} is not supported. Ignoring database"); |
330 | 377 | } |
331 | 378 | } |
332 | 379 | catch |
333 | 380 | { |
334 | | - // File is likely corrupted. |
335 | | - // This is no big deal except that cleanup won't occur. |
336 | | - dbFiles = null; |
| 381 | + // DB File is likely corrupted. |
| 382 | + // This is no big deal except that cleanup won't occur and this could result in files not written by the current Sharpmake run to not being deleted. |
337 | 383 | } |
338 | 384 | } |
339 | | - return dbFiles; |
| 385 | + return null; |
340 | 386 | } |
341 | 387 |
|
342 | 388 | private static string GetDatabaseFilename(string dbSuffix) |
343 | 389 | { |
344 | 390 | if (!string.IsNullOrWhiteSpace(s_overrideFilesAutoCleanupDBPath)) |
345 | 391 | return s_overrideFilesAutoCleanupDBPath; |
346 | 392 |
|
347 | | - string databaseFilename = Path.Combine(FilesAutoCleanupDBPath, $"{s_filesAutoCleanupDBPrefix}{dbSuffix}.bin"); |
| 393 | + string databaseFilename = Path.Combine(FilesAutoCleanupDBPath, $"{s_filesAutoCleanupDBPrefix}{dbSuffix}.json"); |
348 | 394 | return databaseFilename; |
349 | 395 | } |
350 | 396 |
|
@@ -475,35 +521,26 @@ internal static void ExecuteFilesAutoCleanup(bool addDBToAlternateDB) |
475 | 521 | } |
476 | 522 | } |
477 | 523 |
|
478 | | - // Write database if needed |
479 | | - if (newDbFiles.Count > 0) |
480 | | - { |
481 | | - using (Stream writeStream = new FileStream(databaseFilename, FileMode.Create, FileAccess.Write, FileShare.None)) |
482 | | - using (BinaryWriter binWriter = new BinaryWriter(writeStream)) |
483 | | - { |
484 | | - // Write version number |
485 | | - int version = (int)DBVersion.Version; |
486 | | - binWriter.Write(version); |
487 | | - |
488 | | - // Write the list of files. |
489 | | - string dbAsJson = System.Text.Json.JsonSerializer.Serialize(newDbFiles, GetCleanupDatabaseJsonSerializerOptions()); |
490 | | - binWriter.Write(dbAsJson); |
491 | | - binWriter.Flush(); |
492 | | - } |
493 | | - |
494 | | - if (addDBToAlternateDB) |
495 | | - _FilesAlternatesAutoCleanupDBFullPaths.Add(databaseFilename); |
496 | | - } |
497 | | - else |
498 | | - { |
499 | | - TryDeleteFile(databaseFilename); |
500 | | - } |
| 524 | + WriteCleanupDatabase(databaseFilename, newDbFiles); |
| 525 | + if (addDBToAlternateDB) |
| 526 | + _FilesAlternatesAutoCleanupDBFullPaths.Add(databaseFilename); |
501 | 527 |
|
502 | 528 | // We are done! Clear the list of files to avoid problems as this context is now considered as complete. |
503 | 529 | // For example if generating debug solution and then executing normal generation |
504 | 530 | s_writtenFiles.Clear(); |
505 | 531 | } |
506 | 532 |
|
| 533 | + private static void WriteCleanupDatabase(string databaseFilename, Dictionary<string, DateTime> generatedFiles) |
| 534 | + { |
| 535 | + CleanupDatabaseContent dbContent = new CleanupDatabaseContent |
| 536 | + { |
| 537 | + DBVersion = CleanupDatabaseContent.DBVersions.CurrentVersion, |
| 538 | + Data = generatedFiles |
| 539 | + }; |
| 540 | + string jsonString = System.Text.Json.JsonSerializer.Serialize(dbContent, GetCleanupDatabaseJsonSerializerOptions()); |
| 541 | + File.WriteAllText(databaseFilename, jsonString); |
| 542 | + } |
| 543 | + |
507 | 544 | public static string WinFormSubTypesDbPath = string.Empty; |
508 | 545 | private static readonly string s_winFormSubTypesDbPrefix = "winformssubtypesdb"; |
509 | 546 |
|
|
0 commit comments