Skip to content

Commit 35e88cc

Browse files
CopilotBornToBeRootCopilot
authored
Use filename timestamp for backup ordering and move to Utilities (#3284)
* Initial plan * Extract date from filename for backup ordering Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Use InvariantCulture and specific exception handling Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Move ExtractTimestampFromFilename to TimestampHelper in Utilities Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Update comment to match specific exception handling Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> * Feature: Improve check * Update Source/NETworkManager.Utilities/TimestampHelper.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Source/NETworkManager.Utilities/TimestampHelper.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Source/NETworkManager.Utilities/TimestampHelper.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update TimestampHelper.cs * Update TimestampHelper.cs --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 39ac33e commit 35e88cc

File tree

2 files changed

+53
-5
lines changed

2 files changed

+53
-5
lines changed

Source/NETworkManager.Settings/SettingsManager.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public static void Load()
180180
// Create a backup of the legacy XML file and delete the original
181181
Backup(legacyFilePath,
182182
GetSettingsBackupFolderLocation(),
183-
$"{TimestampHelper.GetTimestamp()}_{GetLegacySettingsFileName()}");
183+
TimestampHelper.GetTimestampFilename(GetLegacySettingsFileName()));
184184

185185
File.Delete(legacyFilePath);
186186

@@ -279,7 +279,7 @@ private static void CreateDailyBackupIfNeeded()
279279
// Create backup
280280
Backup(GetSettingsFilePath(),
281281
GetSettingsBackupFolderLocation(),
282-
$"{TimestampHelper.GetTimestamp()}_{GetSettingsFileName()}");
282+
TimestampHelper.GetTimestampFilename(GetSettingsFileName()));
283283

284284
// Cleanup old backups
285285
CleanupBackups(GetSettingsBackupFolderLocation(),
@@ -295,21 +295,23 @@ private static void CreateDailyBackupIfNeeded()
295295
/// specified maximum, are retained.
296296
/// </summary>
297297
/// <remarks>This method removes the oldest backup files first, keeping only the most recent backups as
298-
/// determined by file creation time. It is intended to prevent excessive accumulation of backup files and manage
298+
/// determined by the timestamp in the filename. It is intended to prevent excessive accumulation of backup files and manage
299299
/// disk space usage.</remarks>
300300
/// <param name="backupFolderPath">The full path to the directory containing the backup files to be managed. Cannot be null or empty.</param>
301301
/// <param name="settingsFileName">The file name pattern used to identify backup files for cleanup.</param>
302302
/// <param name="maxBackupFiles">The maximum number of backup files to retain. Must be greater than zero.</param>
303303
private static void CleanupBackups(string backupFolderPath, string settingsFileName, int maxBackupFiles)
304304
{
305+
// Get all backup files sorted by timestamp (newest first)
305306
var backupFiles = Directory.GetFiles(backupFolderPath)
306-
.Where(f => f.EndsWith(settingsFileName) || f.EndsWith(GetLegacySettingsFileName()))
307-
.OrderByDescending(f => File.GetCreationTime(f))
307+
.Where(f => (f.EndsWith(settingsFileName) || f.EndsWith(GetLegacySettingsFileName())) && TimestampHelper.IsTimestampedFilename(Path.GetFileName(f)))
308+
.OrderByDescending(f => TimestampHelper.ExtractTimestampFromFilename(Path.GetFileName(f)))
308309
.ToList();
309310

310311
if (backupFiles.Count > maxBackupFiles)
311312
Log.Info($"Cleaning up old backup files... Found {backupFiles.Count} backups, keeping the most recent {maxBackupFiles}.");
312313

314+
// Delete oldest backups until the maximum number is reached
313315
while (backupFiles.Count > maxBackupFiles)
314316
{
315317
var fileToDelete = backupFiles.Last();

Source/NETworkManager.Utilities/TimestampHelper.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Globalization;
3+
using System.IO;
24

35
namespace NETworkManager.Utilities;
46

@@ -8,4 +10,48 @@ public static string GetTimestamp()
810
{
911
return DateTime.Now.ToString("yyyyMMddHHmmss");
1012
}
13+
14+
/// <summary>
15+
/// Generates a filename by prefixing the specified filename with a timestamp string.
16+
/// </summary>
17+
/// <param name="fileName">The original filename to be prefixed with a timestamp. Cannot be null or empty.</param>
18+
/// <returns>A string containing the timestamp followed by an underscore and the original filename.</returns>
19+
public static string GetTimestampFilename(string fileName)
20+
{
21+
return $"{GetTimestamp()}_{fileName}";
22+
}
23+
24+
/// <summary>
25+
/// Determines whether the specified file name begins with a valid timestamp in the format "yyyyMMddHHmmss".
26+
/// </summary>
27+
/// <remarks>This method checks only the first 14 characters of the file name for a valid timestamp and
28+
/// does not validate the remainder of the file name.</remarks>
29+
/// <param name="fileName">The file name to evaluate. The file name is expected to start with a 14-digit timestamp followed by an
30+
/// underscore and at least one additional character.</param>
31+
/// <returns>true if the file name starts with a valid timestamp in the format "yyyyMMddHHmmss"; otherwise, false.</returns>
32+
public static bool IsTimestampedFilename(string fileName)
33+
{
34+
// Ensure the filename is long enough to contain a timestamp, an underscore, and at least one character after it
35+
if (fileName.Length < 16)
36+
return false;
37+
38+
var timestampString = fileName.Substring(0, 14);
39+
40+
return DateTime.TryParseExact(timestampString, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None, out _);
41+
}
42+
43+
/// <summary>
44+
/// Extracts the timestamp from a filename that starts with a timestamp prefix.
45+
/// </summary>
46+
/// <remarks>Filenames are expected to start with yyyyMMddHHmmss_* format (14 characters).
47+
/// This method extracts the timestamp portion and parses it as a DateTime.</remarks>
48+
/// <param name="fileName">The full path to the file or just the filename.</param>
49+
/// <returns>The timestamp extracted from the filename.</returns>
50+
public static DateTime ExtractTimestampFromFilename(string fileName)
51+
{
52+
// Extract the timestamp prefix (yyyyMMddHHmmss format, 14 characters)
53+
var timestampString = fileName.Substring(0, 14);
54+
55+
return DateTime.ParseExact(timestampString, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
56+
}
1157
}

0 commit comments

Comments
 (0)