From 7a2492f14b5db930233ccfcfada71c731483a021 Mon Sep 17 00:00:00 2001 From: "phares@iscn5cg20977xq" Date: Mon, 29 Sep 2025 16:06:06 -0700 Subject: [PATCH] rename-then-find-first-and-last (Day-Helper-2025-09-26) --- .vscode/launch.json | 14 ++ ADO2025/PI7/Helper-2025-09-26.cs | 272 +++++++++++++++++++++++++++++++ Day/HelperDay.cs | 2 + File-Folder-Helper.csproj | 2 +- 4 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 ADO2025/PI7/Helper-2025-09-26.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 064b5ae..78dfa31 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,6 +11,20 @@ "preLaunchTask": "Build", "program": "${workspaceFolder}/bin/Debug/net8.0/win-x64/File-Folder-Helper.dll", "args": [ + "s", + "X", + "X:/Production/Logs/EAF-Warn-Error-002-014-004~X:/Production/Logs/EAF-Info-Warn-002-059-000~X:/Production/Logs/EAF-Info-Warn-002-060-000~X:/Production/Logs/EAF-Info-Warn-002-061-001", + "Day-Helper-2025-09-26", + "EAF_INFO*.lo*~EAF_WARN*.lo*", + "S1F4 W-Bit", + "yyyy-MM-dd HH:mm:ss,fff", + "0", + "10", + "EAF_INFO*.lo*~EAF_WARN*.lo*", + "DF_Error*.lo*~DF_Notification*.lo*~DF_Unit*.lo*", + "2025-*.log", + "X:/Production/Logs/EAF-Warn-Error-002-014-004~X:/Production/Logs/EAF-Info-Warn-002-059-000~X:/Production/Logs/EAF-Info-Warn-002-060-000~X:/Production/Logs/EAF-Info-Warn-002-061-001", + "X:/Production/Logs/EDA_004_016_001~X:/Production/Logs/EDA_004_021_000", "s", "X", "A:/6-Other-Large-Z/Linux-Ubuntu-Affirm/etc/nginx/include~B:/6-Other-Large-Z/Linux-Ubuntu-BCHS/etc/nginx/include~J:/6-Other-Large-Z/Linux-Ubuntu-JMLC/etc/nginx/include~P:/6-Other-Large-Z/Linux-Ubuntu-Phares/etc/nginx/include", diff --git a/ADO2025/PI7/Helper-2025-09-26.cs b/ADO2025/PI7/Helper-2025-09-26.cs new file mode 100644 index 0000000..5cc5dc1 --- /dev/null +++ b/ADO2025/PI7/Helper-2025-09-26.cs @@ -0,0 +1,272 @@ +using Microsoft.Extensions.Logging; +using System.Globalization; + +namespace File_Folder_Helper.ADO2025.PI7; + +internal static partial class Helper20250926 { + + internal static void RenameThenFindFirstAndLast(ILogger logger, List args) { + logger.LogInformation(args[0]); + logger.LogInformation(args[1]); + logger.LogInformation(args[2]); + logger.LogInformation(args[3]); + logger.LogInformation(args[4]); + logger.LogInformation(args[5]); + const char star = '*'; + const char underscore = '_'; + string dateFormat = args[4]; + string searchString = args[3]; + int seconds = int.Parse(args[5]); + string[] searchPatterns = args[2].Split('~'); + string key = searchString.ToLower().Split(' ')[0]; + string[] sourceDirectories = Path.GetFullPath(args[0]).Split('~'); + if (args.Count == 999) { + Redo(logger, star, underscore, dateFormat, searchString, key, searchPatterns, sourceDirectories); + } + Rename(logger, star, underscore, dateFormat, searchString, key, searchPatterns, sourceDirectories); + if (seconds > 0) { + FindFirstAndLast(logger, star, underscore, dateFormat, searchString, seconds, searchPatterns, sourceDirectories); + } + } + + private static void Redo(ILogger logger, char star, char underscore, string dateFormat, string searchString, string key, string[] searchPatterns, string[] sourceDirectories) { + bool found; + string check; + string[] files; + string[] lines; + string fileName; + string checkFile; + string checkPath; + DateTime lastDate; + DateTime firstDate; + string directoryName; + string[] directories; + string? directoryPath; + foreach (string sourceDirectory in sourceDirectories) { + directories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string searchPattern in searchPatterns) { + if (searchPattern.Contains(underscore) || !searchPattern.Contains(star)) { + throw new Exception($"{nameof(searchPattern)} must not contain {underscore} and must contain {star}"); + } + foreach (string directory in directories) { + directoryName = Path.GetFileName(directory); + files = Directory.GetFiles(directory, searchPattern, SearchOption.AllDirectories); + logger.LogInformation("With search pattern '{SearchPattern}' found {files} file(s)", searchPattern, files.Length); + foreach (string file in files) { + found = false; + lastDate = DateTime.MinValue; + firstDate = DateTime.MinValue; + fileName = Path.GetFileName(file); + directoryPath = Path.GetDirectoryName(file); + if (string.IsNullOrEmpty(directoryPath)) { + logger.LogInformation("skipped (empty) '{directoryPath}'", directoryPath); + continue; + } + try { + lines = File.ReadAllLines(file); + foreach (string line in lines) { + if (!found && line.Contains(searchString)) { + found = true; + } + if (line.Length < dateFormat.Length) { + continue; + } + check = line[..dateFormat.Length]; + if (!DateTime.TryParseExact(check, dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime logDate)) { + continue; + } + if (firstDate == DateTime.MinValue) { + firstDate = logDate; + } + lastDate = logDate; + } + if (!found) { + checkFile = $"{directoryName}_{firstDate:yyyy-MM-dd_HH-mm-ss}---{lastDate:yyyy-MM-dd_HH-mm-ss}.log"; + } else { + checkFile = $"{directoryName}_{firstDate:yyyy-MM-dd_HH-mm-ss}---{lastDate:yyyy-MM-dd_HH-mm-ss}~~~{key}.log"; + } + checkPath = Path.Combine(directoryPath, checkFile); + if (checkFile == fileName) { + logger.LogDebug("skipped (match) '{checkFile}'", checkFile); + } else if (File.Exists(checkPath)) { + logger.LogInformation("skipped (exists) '{checkPath}'", checkPath); + } else { + logger.LogInformation("rename to '{checkPath}'", checkPath); + File.Move(file, checkPath); + } + } catch { + logger.LogWarning("skipped (error) {TotalHours} hour(s) -> '{FileInfo}'", file, (DateTime.Now - new FileInfo(file).LastWriteTime).TotalHours); + } + } + } + } + } + } + + private static void Rename(ILogger logger, char star, char underscore, string dateFormat, string searchString, string key, string[] searchPatterns, string[] sourceDirectories) { + bool found; + string check; + string[] files; + string[] lines; + string checkFile; + string checkPath; + DateTime lastDate; + string[] segments; + DateTime firstDate; + string[] segmentsB; + string directoryName; + string[] directories; + string destinationDirectory; + FileInfo[] fileInfoCollection; + foreach (string sourceDirectory in sourceDirectories) { + directories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string searchPattern in searchPatterns) { + if (!searchPattern.Contains(underscore) || !searchPattern.Contains(star)) { + throw new Exception($"{nameof(searchPattern)} must contain {underscore} and {star}"); + } + segments = searchPattern.Split(star); + segmentsB = segments[0].Split(underscore); + foreach (string directory in directories) { + directoryName = Path.GetFileName(directory); + destinationDirectory = Path.Combine(directory, segmentsB[0], segmentsB[1]); + if (!Directory.Exists(destinationDirectory)) { + _ = Directory.CreateDirectory(destinationDirectory); + } + files = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly); + logger.LogInformation("With search pattern '{SearchPattern}' found {files} file(s)", searchPattern, files.Length); + fileInfoCollection = files.Select(f => new FileInfo(f)).ToArray(); + foreach (FileInfo fileInfo in fileInfoCollection.OrderBy(f => f.LastWriteTime)) { + if (fileInfo.Length == 0) { + logger.LogDebug("skipped (0k) '{FileInfo}'", fileInfo.FullName); + continue; + } else if (fileInfo.LastWriteTime > DateTime.Now.AddMinutes(-1)) { + logger.LogDebug("skipped (too new) '{FileInfo}'", fileInfo.FullName); + continue; + } + found = false; + lastDate = DateTime.MinValue; + firstDate = DateTime.MinValue; + try { + lines = File.ReadAllLines(fileInfo.FullName); + foreach (string line in lines) { + if (!found && line.Contains(searchString)) { + found = true; + } + if (line.Length < dateFormat.Length) { + continue; + } + check = line[..dateFormat.Length]; + if (!DateTime.TryParseExact(check, dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime logDate)) { + continue; + } + if (firstDate == DateTime.MinValue) { + firstDate = logDate; + } + lastDate = logDate; + } + if (!found) { + checkFile = $"{directoryName}_{firstDate:yyyy-MM-dd_HH-mm-ss}---{lastDate:yyyy-MM-dd_HH-mm-ss}.log"; + } else { + checkFile = $"{directoryName}_{firstDate:yyyy-MM-dd_HH-mm-ss}---{lastDate:yyyy-MM-dd_HH-mm-ss}~~~{key}.log"; + } + checkPath = Path.Combine(destinationDirectory, checkFile); + if (checkFile == fileInfo.Name) { + logger.LogDebug("skipped (match) '{checkFile}'", checkFile); + } else if (File.Exists(checkPath)) { + logger.LogInformation("skipped (exists) '{checkPath}'", checkPath); + } else { + logger.LogInformation("rename to '{checkPath}'", checkPath); + File.Move(fileInfo.FullName, checkPath); + } + } catch { + logger.LogWarning("skipped (error) {TotalHours} hour(s) -> '{FileInfo}'", (DateTime.Now - fileInfo.LastWriteTime).TotalHours, fileInfo.FullName); + } + } + Helpers.HelperDeleteEmptyDirectories.DeleteEmptyDirectories(logger, directory); + } + } + } + } + + private static void FindFirstAndLast(ILogger logger, char star, char underscore, string dateFormat, string searchString, int seconds, string[] searchPatterns, string[] sourceDirectories) { + string line; + string check; + string[] files; + string[] lines; + DateTime lastDate; + double totalHours; + string[] segments; + TimeSpan timeSpan; + DateTime firstDate; + string[] segmentsB; + string directoryName; + string[] directories; + string searchPatternB; + string destinationDirectory; + FileInfo[] fileInfoCollection; + DateTime logDate = DateTime.MinValue; + foreach (string sourceDirectory in sourceDirectories) { + directories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string searchPattern in searchPatterns) { + if (!searchPattern.Contains(underscore) || !searchPattern.Contains(star)) { + throw new Exception($"{nameof(searchPattern)} must contain {underscore} and {star}"); + } + segments = searchPattern.TrimEnd(star).Split(star); + segmentsB = segments[0].Split(underscore); + foreach (string directory in directories) { + directoryName = Path.GetFileName(directory); + destinationDirectory = Path.Combine(directory, segmentsB[0], segmentsB[1]); + if (!Directory.Exists(destinationDirectory)) { + logger.LogInformation("skipped (doesn't exist) '{destinationDirectory}'", destinationDirectory); + continue; + } + searchPatternB = $"*{segments[^1]}*"; + files = Directory.GetFiles(destinationDirectory, searchPatternB, SearchOption.TopDirectoryOnly); + logger.LogInformation("For {destinationDirectory} with search pattern '{SearchPatternB}' found {files} file(s)", destinationDirectory, searchPatternB, files.Length); + fileInfoCollection = files.Select(f => new FileInfo(f)).ToArray(); + foreach (FileInfo fileInfo in fileInfoCollection.OrderBy(f => f.LastWriteTime)) { + if (fileInfo.Length == 0) { + logger.LogDebug("skipped (0k) '{FileInfo}'", fileInfo.FullName); + continue; + } else if (fileInfo.LastWriteTime > DateTime.Now.AddMinutes(-1)) { + logger.LogDebug("skipped (too new) '{FileInfo}'", fileInfo.FullName); + continue; + } + lastDate = DateTime.MinValue; + firstDate = DateTime.MinValue; + try { + lines = File.ReadAllLines(fileInfo.FullName); + for (int i = 0; i < lines.Length; i++) { + line = lines[i]; + if (!line.Contains(searchString) || lines[i - 1].Length < dateFormat.Length) { + continue; + } + check = lines[i - 1][..dateFormat.Length]; + if (!DateTime.TryParseExact(check, dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out logDate)) { + continue; + } + timeSpan = logDate - lastDate; + if (firstDate == DateTime.MinValue || timeSpan.TotalSeconds > seconds) { + if (firstDate != DateTime.MinValue) { + totalHours = Math.Round((lastDate - firstDate).TotalHours, 2); + logger.LogInformation("Ran for {totalHours} hour(s) {logDate} - {firstDate} {file}", totalHours, logDate.ToString("HH:mm:ss"), firstDate.ToString("HH:mm:ss"), fileInfo.FullName[directory.Length..]); + } + firstDate = logDate; + } + lastDate = logDate; + } + if (firstDate != DateTime.MinValue && logDate != DateTime.MinValue) { + totalHours = Math.Round((lastDate - firstDate).TotalHours, 2); + logger.LogInformation("Ran for {totalHours} hour(s) {logDate} - {firstDate} {file}", totalHours, logDate.ToString("HH:mm:ss"), firstDate.ToString("HH:mm:ss"), fileInfo.FullName[directory.Length..]); + } + } catch { + logger.LogWarning("skipped (error) {TotalHours} hour(s) -> '{FileInfo}'", (DateTime.Now - fileInfo.LastWriteTime).TotalHours, fileInfo.FullName); + } + } + Helpers.HelperDeleteEmptyDirectories.DeleteEmptyDirectories(logger, directory); + } + } + } + } + +} \ No newline at end of file diff --git a/Day/HelperDay.cs b/Day/HelperDay.cs index 12e0e74..b4d5aa1 100644 --- a/Day/HelperDay.cs +++ b/Day/HelperDay.cs @@ -187,6 +187,8 @@ internal static class HelperDay ADO2025.PI6.Helper20250726.CopyToCombinedEnumAndIndexFormat(logger, args); else if (args[1] == "Day-Helper-2025-09-08") ADO2025.PI7.Helper20250908.DebugProxyPass(logger, args); + else if (args[1] == "Day-Helper-2025-09-26") + ADO2025.PI7.Helper20250926.RenameThenFindFirstAndLast(logger, args); else throw new Exception(appSettings.Company); } diff --git a/File-Folder-Helper.csproj b/File-Folder-Helper.csproj index 744ee4c..ebf0771 100644 --- a/File-Folder-Helper.csproj +++ b/File-Folder-Helper.csproj @@ -18,7 +18,7 @@ - +