in Sharpmake/Util.cs [449:560]
internal static void ExecuteFilesAutoCleanup(bool addDBToAlternateDB)
{
if (!FilesAutoCleanupActive && !s_forceFilesCleanup)
return; // Auto cleanup not active. Nothing to do.
if (string.IsNullOrWhiteSpace(s_overrideFilesAutoCleanupDBPath) && !Directory.Exists(FilesAutoCleanupDBPath))
throw new Exception($"Unable to find directory {FilesAutoCleanupDBPath} used to store auto-cleanup database. Is proper path set?");
string databaseFilename = GetDatabaseFilename(FilesAutoCleanupDBSuffix);
Dictionary<string, DateTime> dbFiles = ReadCleanupDatabase(databaseFilename);
// Note: We must take into account all databases when doing the cleanup otherwise we might end up deleting files still used in other contexts.
List<Dictionary<string, DateTime>> alternateDatabases = new List<Dictionary<string, DateTime>>();
// Try to load all alternate db contexts
var alternateDBFullPaths = FilesAlternatesAutoCleanupDBSuffixes.Select(alternateDBSuffix => GetDatabaseFilename(alternateDBSuffix))
.Concat(_FilesAlternatesAutoCleanupDBFullPaths.AsEnumerable());
foreach (string alternateDatabaseFilename in alternateDBFullPaths)
{
Dictionary<string, DateTime> alternateDBFiles = ReadCleanupDatabase(alternateDatabaseFilename);
if (alternateDBFiles != null)
alternateDatabases.Add(alternateDBFiles);
}
Dictionary<string, DateTime> newDbFiles = new Dictionary<string, DateTime>(s_writtenFiles, StringComparer.InvariantCultureIgnoreCase);
if (dbFiles != null)
{
// Deleting all files that are no longer used.
DateTime now = DateTime.Now;
foreach (KeyValuePair<string, DateTime> filenameDate in dbFiles)
{
if (s_forceFilesCleanup)
{
if (!File.Exists(filenameDate.Key))
continue;
LogWrite(@"Force deleting '{0}'", filenameDate.Key);
if (!TryDeleteFile(filenameDate.Key, removeIfReadOnly: true))
{
// Failed to delete the file... Keep it for now... Maybe later we will be able to delete it!
LogWrite(@"Failed to delete '{0}'", filenameDate.Key);
}
continue;
}
if (newDbFiles.ContainsKey(filenameDate.Key))
continue;
if (FilesAutoCleanupIgnoredEndings.Any(x => filenameDate.Key.EndsWith(x, StringComparison.OrdinalIgnoreCase)))
continue;
TimeSpan diff = now - filenameDate.Value;
if (diff >= FilesAutoCleanupDelay)
{
if (!File.Exists(filenameDate.Key))
continue;
bool foundFileInAlternateDatabase = false;
// Check alternateDatabases files
foreach (var alternateDB in alternateDatabases)
{
if (alternateDB.ContainsKey(filenameDate.Key))
{
// Another database still uses the file. Simply remove the file from the current database and don't attempt to delete this file.
foundFileInAlternateDatabase = true;
break;
}
}
if (!foundFileInAlternateDatabase)
{
if (!FilesToBeExplicitlyRemovedFromDB.Contains(filenameDate.Key))
{
// Exclude files that were modified since the beginning of the current Sharpmake run.
// This should avoid regressions when a generated file is not added to cleanup database anymore.
// Example: replacing a call to Util.FileWriteIfDifferent() with File.WriteAll()
// From the previous run, Util.FileWriteIfDifferent() added the file in the cleanup database.
// In the new run, File.WriteAll() wrote the file, but the cleanup system would want to delete it.
if (File.GetLastWriteTime(filenameDate.Key) >= ProgramStartTime)
{
LogWrite(@"Skip deleting old file (updated during this run): {0}", filenameDate.Key);
newDbFiles.Add(filenameDate.Key, filenameDate.Value);
continue;
}
LogWrite(@"Deleting old file: {0}", filenameDate.Key);
if (!TryDeleteFile(filenameDate.Key))
{
// Failed to delete the file... Keep it for now... Maybe later we will be able to delete it!
LogWrite(@"Failed to delete {0}. Keep it in the database.", filenameDate.Key);
newDbFiles.Add(filenameDate.Key, filenameDate.Value);
}
}
}
}
else
{
LogWrite(@"Skip deleting old file (delayed): {0}", filenameDate.Key);
newDbFiles.Add(filenameDate.Key, filenameDate.Value);
}
}
}
WriteCleanupDatabase(databaseFilename, newDbFiles);
if (addDBToAlternateDB)
_FilesAlternatesAutoCleanupDBFullPaths.Add(databaseFilename);
// We are done! Clear the list of files to avoid problems as this context is now considered as complete.
// For example if generating debug solution and then executing normal generation
s_writtenFiles.Clear();
}