3 Commits

8 changed files with 441 additions and 198 deletions

193
.vscode/launch.json vendored
View File

@ -11,68 +11,12 @@
"preLaunchTask": "Build",
"program": "${workspaceFolder}/bin/Debug/net8.0/win-x64/File-Folder-Helper.dll",
"args": [
"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",
"Day-Helper-2025-09-08",
"*.conf",
"/etc/nginx/include/",
"server_name",
"proxy_pass~root",
"oauth2",
"s",
"X",
"P:/6-Other-Large-Z/Current-Results/A2)People/c9dbce3b/([])/File-Folder-Helper/638443643487798783/638443643487798783",
"Day-Helper-2024-05-18",
"people.json",
"person",
"ownerId,name,birthDate",
"c76905af-c06a-4a78-a9a7-c32f5b58e793",
"yyyy-MM-dd",
"1900-01-01",
"s",
"X",
"P:/1-Images-A/Images-0b793904",
"Day-Helper-2025-07-26",
"4e+9",
"L:/Git/AA/Rename/.vscode/.UserSecrets/secrets.json",
".avif~.bmp~.gif~.heic~.insp~.jp2~.jpe~.jpeg~.jpg~.jxl~.png~.psd~.raw~.rw2~.svg~.tif~.tiff~.webp~.3gp~.3gpp~.avi~.dvr-ms~.flv~.insv~.m2t~.m2ts~.m4v~.mkv~.mov~.mp4~.mpe~.mpeg~.mpg~.mts~.ts~.webm~.wmv",
"P:/6-Other-Large-Z/Current-Results/C)Resize/0b793904/Original",
"(helper)",
"s",
"X",
"P:/1-Images-A/Images-0b793904",
"Day-Helper-2024-12-17",
".job.json",
"thumbs.db~sync.ffs_db~verify.json~.html",
"I:/0-ISO-A",
"D:/5-Other-Small/Disk/Snap2HTML/Snap2HTML.exe",
"s",
"X",
"P:/Tmp/Phares/Helper-2025-07-20",
"Day-Helper-2025-07-20",
"871467010009.jpg",
"L:/Git/AA/Rename/.vscode/.UserSecrets/secrets.json",
"A:/()/638432064000000000.51/1401-08-03_02/2023/X+441981864000000000/871467010009.444090906.jpg.png",
"*.png",
"D:/{}/DisneyWorld 2019/Magic Kingdom/871467010009.jpg.xmp",
"*.xmp",
"{}-output",
"s",
"X",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/Log",
"Day-Helper-2025-07-10",
"R*",
"EAF_INFO*",
"s",
"X",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/JavaScriptObjectNotation",
"Day-Helper-2025-07-09",
"Day-Helper-2025-10-22",
"*.json",
"987654321",
".agg",
"id93,vp93,ProcessState,id154,vp154,SystemState,id78,vp78,LL1State,id83,vp83,LL2State,id176,vp176,TotalWaferCount,id80,vp80,LL1Lotid,id85,vp85,LL2Lotid,id153,vp153,PPSTEPNAME,id221,vp221,LeftDefaultRecipe,id222,vp222,RightDefaultRecipe,id223,vp223,RecipeCompleteMsg",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/Reactor",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/WorkWeek",
"s",
"X",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/PollPath",
@ -86,138 +30,7 @@
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/Markdown",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/KeyValuePairs",
"654321",
"s",
"s",
"X",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/R55",
"Day-Helper-2023-11-30",
"yyMMddhhmmssfff",
"\"vp154\"",
"s",
"X",
"P:/Tmp/Phares/Pictures/2023 TI2023.6 Fall Samsung",
"Day-Helper-2025-07-05",
"x-653889110721.jpg~401223300869.jpg",
"3648,2736,1~3024,4032,6",
"0.341694,0.599963,0.1642,0.279605~0.552357,0.65095,0.195175,0.32383~0.31002,0.42328,0.0379464,0.0459656",
"0.259594,0.460161,0.1642,0.279605~0.45477,0.489035,0.195175,0.32383~0.328993,0.446263,0.0379464,0.0459656",
"9",
"x-825511723~x-444522128~831410304",
"X",
"F:/0-ISO-A",
"Day-Helper-2025-06-28",
"*.iso",
"F",
"s",
"X",
"D:/5-Other-Small",
"Day-Helper-2024-12-17",
".job.json",
"thumbs.db~sync.ffs_db~verify.json~.html",
"D:/0-ISO-A",
"D:/5-Other-Small/Proxmox/Snap2HTML/Snap2HTML.exe",
"s",
"M",
"D:/5-Other-Small/Notes/EC-Documentation",
"-d",
"D:/5-Other-Small/Notes/EC-Documentation/.vscode/helper",
"s",
"X",
"D:/5-Other-Small/Proxmox/DiskInfo",
"Day-Helper-2025-06-18",
"*.json",
"D:/5-Other-Small/Proxmox/Disk-Info-Old",
"-2025-",
"1",
"s",
"X",
"D:/Tmp",
"Day-Helper-2025-06-02",
"infineon\\MESPhares",
"BACKLOG~BIORAD2~BIORAD3~BIORAD4~BIORAD5~CDE4~CDE5~CDE6~DEP08CEPIEPSILON~DEP08SIASM~DEP08SIHTRPLC~EC~HGCV1~HGCV2~HGCV3~MESAFIBACKLOG~MET06AWCT~MET08ANLYSDIFAAST230~MET08AWCT~MET08DDUPSFS6420~MET08DDUPSP1TBI~MET08RESIHGCV~MET08RESIMAPCDE~MET08RESISRP2100~MET08THFTIRQS408M~MET08THFTIRSTRATUS~METCLIMATEC~R29~R32~R36~R47~R55~R57~R61~R62~R65~R70~R72~R73~R74~R75~R77~SP101~SPV01~SRP~TENCOR1~TENCOR2~TENCOR3~TRENDLOG~WC6INCH1~WC6INCH2~WC6INCH3~WC6INCH4~WC8INCH1~WC8INCH2~WC8INCH3",
"s",
"X",
"D:/5-Other-Small/Proxmox/ffnm",
"Day-Helper-2025-05-21",
"*.pdf",
"*.md",
"2",
"MM-dd-yy",
"Trans Date~Effective Date~Description~Withdrawal Deposit~Balance",
"s",
"X",
"D:/Tmp/phares/VisualStudioCode",
"Day-Helper-2025-05-19",
"D:/Tmp/phares/VisualStudioCode/.vscode/input.json",
"s",
"X",
"D:/Tmp/phares/VisualStudioCode",
"Day-Helper-2025-05-19",
"D:/Tmp/phares/VisualStudioCodeLeft",
"z-include-patterns.nsv",
"z-exclude-patterns.nsv",
"http://localhost:5004",
"/api/SyncV1/?",
",L",
".G",
"+~G~~L~+~Custom-Default",
"",
"+~G~~G~-~Mirror",
"+~G~~~~Update",
"+~G~~L~+~Custom-Default",
"-~G~~G~+~Custom-A",
"-~L~~L~+~Custom-B",
"+~L~~L~-~Custom-C",
"s",
"X",
"\\\\mesfs.infineon.com\\EC_Characterization_Si\\Archive\\BIORAD4\\2025_Week_16\\2025-04-17",
"Day-Helper-2025-02-19",
"csv-*.pdsf",
"*.pdsf",
"Time,HeaderUniqueId,UniqueId,Date,Wafer,Position,BIORAD4",
",BIORAD4",
",BIORAD4",
"Test|EventId,Date|DateTime,Position|Slot,DeltaThicknessSlotsOneAndTwentyFive|Actual Delta Thick Pts 1 and 25,PercentDeltaThicknessSlotsOneAndTwentyFive|% Delta Thick Pts 1 and 25,MID|Cassette,Lot|Batch,Title|Batch,Wafer|Text,Thickness|Site,MeanThickness|GradeMean,|BIORAD4",
"Time,A_LOGISTICS,B_LOGISTICS,Test,Count,Index,MesEntity,MID,Date,Employee,Lot,PSN,Reactor,Recipe,Cassette,GradeStdDev,HeaderUniqueId,Layer,MeanThickness,PassFail,RDS,Slot,Title,UniqueId,Wafer,Zone,Mean,Position,StdDev,Thickness,ThicknessSlotOne,ThicknessSlotTwentyFive,DeltaThicknessSlotsOneAndTwentyFive,PercentDeltaThicknessSlotsOneAndTwentyFive",
"Time,A_LOGISTICS,B_LOGISTICS,Count,Sequence,MesEntity,Index,Batch,Cassette,DateTime,Destination,Mean,PassFail,Recipe,Reference,Site,Slot,Source,StdDev,Text,GradeMean,GradeStdDev,RDS,PSN,Reactor,Layer,Zone,Employee,InferredLot,Thickness First Slot,Thickness Last Slot,Actual Delta Thick Pts 1 and 25,% Delta Thick Pts 1 and 25,EventId",
"0,1,2,31,3,6,5,8,9,27,7,23,24,13,8,21,-1,25,20,12,22,16,7,-1,19,26,11,16,18,15,-1,-1,29,30",
"s",
"X",
"C:/Users/phares/AppData/Roaming/FreeFileSync",
"Day-Helper-2025-04-21",
"GlobalSettings.xml",
"LastSync|Config",
"s",
"X",
"L:/Tmp/MET08ANLYSDIFAAST230",
"Day-Helper-2025-03-06",
"*.pdsf",
"s",
"X",
"D:/ProgramData/VisualStudioCode|D:/6-Other-Large-Z/Linux-Ubuntu-Phares/home/lphares/dorico",
"Day-Helper-2025-04-07",
"z-include-patterns.nsv",
"z-exclude-patterns.nsv",
"https://isccvm57294f1ed/VisualStudioCode|hxttps://dorico.phares.duckdns.org|hxttps://mestsa006.infineon.com/VisualStudioCode",
"+|G|G|G|-",
"||||",
"666",
"777",
"888",
"999",
"s",
"X",
"C:/Users/PHARES/AppData/Local/IFXApps/gatus",
"Day-Helper-2025-04-04",
"*.json",
".metrics",
"https://messa010ec.infineon.com/metrics",
"gatus_results_endpoint_success",
"666",
"777",
"888",
"999",
""
".json"
],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",

14
.vscode/tasks.json vendored
View File

@ -348,6 +348,20 @@
"label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20",
"problemMatcher": [],
"type": "shell"
},
{
"args": [
"s",
"X",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/JavaScriptObjectNotation",
"Day-Helper-2025-10-22",
"*.json",
"D:/ProgramData/EC_Characterization_Si/Dummy/DEP08CEPIEPSILON/WorkWeek"
],
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
"label": "File-Folder-Helper AOT s X Day-Helper-2025-10-22",
"problemMatcher": [],
"type": "shell"
}
],
"version": "2.0.0"

View File

@ -243,7 +243,7 @@ internal static partial class Helper20240623 {
"-_[,](",
"##_Done",
".kan",
"D:/5-Other-Small/Kanban/Year-Season",
"J:/5-Other-Small/Kanban/Year-Season",
"316940400000"
],
"problemMatcher": []
@ -530,8 +530,8 @@ internal static partial class Helper20240623 {
private static string? GetInferredCheckDirectory(string directory) {
string? result = null;
List<string> directoryNames = [];
DirectoryInfo directoryInfo;
List<string> directoryNames = [];
string? checkDirectory = directory;
directoryNames.Add(Path.GetFileName(checkDirectory));
string pathRoot = Path.GetPathRoot(directory) ?? throw new Exception();
@ -540,7 +540,6 @@ internal static partial class Helper20240623 {
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot) {
break;
}
directoryInfo = new(checkDirectory);
if (!directoryInfo.Exists) {
directoryNames.Add(directoryInfo.Name);
@ -548,10 +547,15 @@ internal static partial class Helper20240623 {
directoryNames.Reverse();
result = string.IsNullOrEmpty(directoryInfo.LinkTarget) ? checkDirectory : directoryInfo.LinkTarget;
for (int j = 0; j < directoryNames.Count; j++) {
result = Path.GetDirectoryName(result) ?? throw new Exception();
result = Path.GetDirectoryName(result);
if (string.IsNullOrEmpty(result)) {
break;
}
}
foreach (string directoryName in directoryNames) {
result = Path.Combine(result, directoryName);
if (!string.IsNullOrEmpty(result)) {
foreach (string directoryName in directoryNames) {
result = Path.Combine(result, directoryName);
}
}
break;
}

View File

@ -155,7 +155,7 @@ internal static partial class Helper20250204 {
string searchPattern = "*.json";
string fullPath = Path.GetFullPath(args[0]);
string sourceDirectory = GetSourceDirectory(fullPath);
string rootDirectory = args.Count < 3 || args[2].Length < 16 ? "D:/5-Other-Small/Kanban-mestsa003/{}" : args[2];
string rootDirectory = args.Count < 3 || args[2].Length < 16 ? "J:/5-Other-Small/Kanban-mestsa003/{}" : args[2];
WriteTaskFile(sourceDirectory, rootDirectory);
string sourceDirectoryName = Path.GetFileName(sourceDirectory);
DirectoryInfo directoryInfo = new(Path.Combine(sourceDirectory, ".kanbn"));

View File

@ -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<Worker> logger, List<string> 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<Worker> 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<Worker> 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<Worker> 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);
}
}
}
}
}

View File

@ -0,0 +1,136 @@
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace File_Folder_Helper.ADO2025.PI7;
internal static partial class Helper20251022 {
private record Root(int Count, JsonElement[] Records, ProcessDataStandardFormat? ProcessDataStandardFormat) {
internal static Root? Get(string file) {
Root? result;
string? json = File.ReadAllText(file);
result = JsonSerializer.Deserialize(json, Helper20251022RootSourceGenerationContext.Default.Root);
if (result is null || result.ProcessDataStandardFormat is null || result.Records.Length == 0) {
result = null;
}
return result;
}
}
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(Root))]
private partial class Helper20251022RootSourceGenerationContext : JsonSerializerContext {
}
[JsonSourceGenerationOptions(WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(JsonElement))]
private partial class Helper20251022JsonElementSourceGenerationContext : JsonSerializerContext {
}
private record ProcessDataStandardFormat([property: JsonPropertyName("Footer")] JsonElement? Footer, [property: JsonPropertyName("LOGISTICS_1")] JsonElement? Logistics);
internal static void CombineFiles(ILogger<Worker> logger, List<string> args) {
logger.LogInformation(args[0]);
logger.LogInformation(args[1]);
logger.LogInformation(args[2]);
logger.LogInformation(args[3]);
string searchPattern = args[2];
string sourceDirectory = Path.GetFullPath(args[0].Split('~')[0]);
string destinationDirectory = Path.GetFullPath(args[3].Split('~')[0]);
string[] directories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly);
ReadOnlyDictionary<string, List<string>> files = GetFiles(logger, searchPattern, directories.AsReadOnly());
CombineFiles(logger, destinationDirectory, files);
}
private static ReadOnlyDictionary<string, List<string>> GetFiles(ILogger<Worker> logger, string searchPattern, ReadOnlyCollection<string> directories) {
Dictionary<string, List<string>> results = [];
string key;
string[] files;
FileInfo fileInfo;
string[] segments;
string weekOfYear;
Calendar calendar = new CultureInfo("en-US").Calendar;
List<string>? collection;
foreach (string directory in directories) {
files = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly);
files = files.OrderBy(l => l).ThenBy(l => l.Length).ToArray();
for (int i = 0; i < files.Length; i++) {
fileInfo = new(files[i]);
segments = fileInfo.Name.Split('_');
if (segments.Length < 2) {
logger.LogWarning("{fileInfoName} does not have enough segments!", fileInfo.Name);
continue;
}
weekOfYear = $"{fileInfo.LastWriteTime.Year}_Week_{calendar.GetWeekOfYear(fileInfo.LastWriteTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}";
key = $"{segments[0]}_{weekOfYear}";
if (!results.TryGetValue(key, out collection)) {
collection = [];
results.Add(key, collection);
}
collection.Add(files[i]);
}
}
return results.AsReadOnly();
}
private static void CombineFiles(ILogger<Worker> logger, string destinationDirectory, ReadOnlyDictionary<string, List<string>> files) {
Root? root;
string json;
string[] lines;
string fileName;
string? jsonFooter;
string? jsonLogistics;
JsonElement jsonElementB;
List<string> segments = [];
List<string> jsonLines = [];
if (!Directory.Exists(destinationDirectory)) {
_ = Directory.CreateDirectory(destinationDirectory);
}
foreach (KeyValuePair<string, List<string>> keyValuePair in files) {
jsonLines.Clear();
fileName = Path.Combine(destinationDirectory, $"{keyValuePair.Key}.json");
foreach (string file in keyValuePair.Value) {
root = Root.Get(file);
if (root is null) {
logger.LogWarning("result is null");
continue;
}
foreach (JsonElement jsonElement in root.Records) {
jsonFooter = root.ProcessDataStandardFormat?.Footer?.ToString();
jsonLogistics = root.ProcessDataStandardFormat?.Logistics?.ToString();
if (string.IsNullOrEmpty(jsonFooter) && string.IsNullOrEmpty(jsonLogistics)) {
jsonLines.Add(jsonElement.ToString());
} else {
segments.Clear();
segments.Add(jsonElement.ToString()[..^1]);
if (!string.IsNullOrEmpty(jsonFooter)) {
segments.Add(",");
lines = jsonFooter[1..^1].Split(Environment.NewLine);
segments.AddRange(lines.Select(l => l.Trim()));
}
if (!string.IsNullOrEmpty(jsonLogistics)) {
segments.Add(",");
lines = jsonLogistics[1..^1].Split(Environment.NewLine);
segments.AddRange(lines.Select(l => l.Trim()));
}
segments.Add("}");
jsonElementB = JsonSerializer.Deserialize(string.Join(' ', segments), Helper20251022JsonElementSourceGenerationContext.Default.JsonElement);
jsonLines.Add(jsonElementB.ToString());
}
}
}
if (jsonLines.Count == 0) {
logger.LogWarning("jsonLines is empty");
continue;
}
json = string.Concat('[', Environment.NewLine, string.Join($",{Environment.NewLine}", jsonLines), Environment.NewLine, ']');
File.WriteAllText(fileName, json);
}
}
}

View File

@ -187,6 +187,10 @@ 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 if (args[1] == "Day-Helper-2025-10-22")
ADO2025.PI7.Helper20251022.CombineFiles(logger, args);
else
throw new Exception(appSettings.Company);
}

View File

@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="Phares.Metadata" Version="8.0.118.14905" />
<PackageReference Include="Phares.Shared" Version="8.0.118.14905" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.19" />
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.21" />
<PackageReference Include="System.Text.Json" Version="9.0.7" />
<PackageReference Include="TextCopy" Version="6.2.1" />
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />