From 23eacb54c100104e8fe4e9ed103ff48540065d9d Mon Sep 17 00:00:00 2001 From: Mike Phares Date: Thu, 29 Aug 2024 08:03:46 -0700 Subject: [PATCH] MoveWaferCounterToArchive ParseKanbn --- .vscode/launch.json | 22 ++- Day/HelperDay.cs | 4 + Day/Q32024/Helper-2024-08-22.cs | 228 ++++++++++++++++++++++++++++++++ Day/Q32024/Helper-2024-08-28.cs | 169 +++++++++++++++++++++++ File-Folder-Helper.csproj | 6 +- 5 files changed, 414 insertions(+), 15 deletions(-) create mode 100644 Day/Q32024/Helper-2024-08-22.cs create mode 100644 Day/Q32024/Helper-2024-08-28.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index cbdf429..30ce4e0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,18 +13,16 @@ "args": [ "s", "X", - "T:/MESAFIBACKLOG/06_SourceCode/MESAFIBACKLOG/Adaptation/.vscode/helper", - "Day-Helper-2024-08-09", - "MES", - "https://tfs.intra.infineon.com", - "/tfs/FactoryIntegration", - "ART SPS", - "/0d06e969-e1f5-4835-a359-620d557c7595/_apis/wit", - "/wiql/3373b300-8de3-4301-9795-e990c3b226f9", - "4n7d2jcql6bkq32f66tohddonfxajkypq66lm5y3zqemtlohawsa", - "FI Backlog Mesa - Request List.json", - "Chase|infineon\\TuckerC,Dakota(SRP)|infineon\\Mitchem,Daniel|infineon\\StieberD,Jonathan|infineon\\Ouellette,Mike|infineon\\Phares", - "Chad B|infineon\\cbecker1,Debra Q|infineon\\Quinones,Jeanne M|infineon\\jmcinty2,Jessica F|infineon\\jfuente1,Jonathon S|infineon\\jsperli1,Justin H|infineon\\jhollan2,Kelly C|infineon\\kclark1,Mark C|infineon\\mcouste1,Marti J|infineon\\mjarsey1,Nik C|infineon\\nclark1,Peyton M|infineon\\McChesne,Ron O|infineon\\HendersS,Susan H|infineon\\HendersS,Tiffany M|infineon\\tmunoz1,Todd C|infineon\\tcarrie1" + "D:/5-Other-Small/Kanban-mestsa003/ART-SPS/113724/.vscode/LogFiles/WaferCounter", + "Day-Helper-2024-08-28", + "*Wafer Counter Verify Log.csv", + "yyyy-MM-dd", + "D:/5-Other-Small/Kanban-mestsa003/ART-SPS/113724/.vscode/WaferCounter", + "*.wc", + "666", + "777", + "888", + "999" ], "cwd": "${workspaceFolder}", "console": "integratedTerminal", diff --git a/Day/HelperDay.cs b/Day/HelperDay.cs index d7be201..43fdaac 100644 --- a/Day/HelperDay.cs +++ b/Day/HelperDay.cs @@ -93,6 +93,10 @@ internal static class HelperDay Day.Q32024.Helper20240809.CreateWorkItems(logger, args); else if (args[1] == "Day-Helper-2024-08-20") Day.Q32024.Helper20240820.MoveFilesWithSleep(logger, args); + else if (args[1] == "Day-Helper-2024-08-22") + Day.Q32024.Helper20240822.ParseKanbn(logger, args); + else if (args[1] == "Day-Helper-2024-08-28") + Day.Q32024.Helper20240828.MoveWaferCounterToArchive(logger, args); else throw new Exception(appSettings.Company); } diff --git a/Day/Q32024/Helper-2024-08-22.cs b/Day/Q32024/Helper-2024-08-22.cs new file mode 100644 index 0000000..f066605 --- /dev/null +++ b/Day/Q32024/Helper-2024-08-22.cs @@ -0,0 +1,228 @@ +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace File_Folder_Helper.Day.Q32024; + +internal static partial class Helper20240822 +{ + + public record Record(string? Title, ReadOnlyCollection Tags, string? Completed); + + public record Root([property: JsonPropertyName("headings")] Heading[] Headings, + [property: JsonPropertyName("lanes")] Lane[] Lanes); + + [JsonSourceGenerationOptions(WriteIndented = true)] + [JsonSerializable(typeof(Root))] + internal partial class Helper20240822RootSourceGenerationContext : JsonSerializerContext + { + } + + public record Welcome2([property: JsonPropertyName("headings")] Heading[] Headings, + [property: JsonPropertyName("lanes")] Lane[] Lanes); + + public record Heading([property: JsonPropertyName("name")] string Name, + [property: JsonPropertyName("heading")] string HeadingHeading); + + public record Lane([property: JsonPropertyName("name")] string Name, + [property: JsonPropertyName("columns")] Column[][] Columns); + + public record Column([property: JsonPropertyName("id")] string Id, + [property: JsonPropertyName("name")] string Name, + [property: JsonPropertyName("description")] string Description, + [property: JsonPropertyName("metadata")] Metadata? Metadata, + [property: JsonPropertyName("subTasks")] SubTask[]? SubTasks, + [property: JsonPropertyName("relations")] object[] Relations, + [property: JsonPropertyName("comments")] Comment[] Comments, + [property: JsonPropertyName("column")] string ColumnColumn, + [property: JsonPropertyName("workload")] long Workload, + [property: JsonPropertyName("progress")] long Progress, + [property: JsonPropertyName("remainingWorkload")] long RemainingWorkload, + [property: JsonPropertyName("dueData")] DueData DueData); + + public record Comment([property: JsonPropertyName("text")] string Text, + [property: JsonPropertyName("date")] DateTimeOffset Date); + + public record DueData([property: JsonPropertyName("completed")] bool Completed, + [property: JsonPropertyName("completedDate")] object CompletedDate, + [property: JsonPropertyName("dueDate")] DateTimeOffset DueDate, + [property: JsonPropertyName("overdue")] bool Overdue, + [property: JsonPropertyName("dueDelta")] long DueDelta, + [property: JsonPropertyName("dueMessage")] string DueMessage); + + public record Metadata([property: JsonPropertyName("assigned")] string Assigned, + [property: JsonPropertyName("created")] DateTimeOffset Created, + [property: JsonPropertyName("progress")] long? Progress, + [property: JsonPropertyName("started")] DateTimeOffset? Started, + [property: JsonPropertyName("status")] string? Status, + [property: JsonPropertyName("tags")] string[]? Tags, + [property: JsonPropertyName("type")] string? Type, + [property: JsonPropertyName("updated")] DateTimeOffset Updated, + [property: JsonPropertyName("due")] DateTimeOffset? Due, + [property: JsonPropertyName("completed")] DateTimeOffset? Completed); + + public record SubTask([property: JsonPropertyName("text")] string Text, + [property: JsonPropertyName("completed")] bool Completed); + + private static ReadOnlyCollection> GetRecords(Column[][] columnCollection) + { + List> results = []; + bool check; + int subTasks; + Column column; + int completed; + List row; + string? subtasks; + List tags; + for (int i = 0; i < int.MaxValue; i++) + { + row = []; + check = false; + foreach (Column[] columns in columnCollection) + { + if (columns.Length <= i) + row.Add(new(null, new([]), null)); + else + { + tags = []; + subTasks = 0; + completed = 0; + column = columns[i]; + if (!check) + check = true; + if (column.Metadata?.Tags is not null && column.Metadata.Tags.Length != 0) + { + foreach (string tag in column.Metadata.Tags) + tags.Add(tag); + } + if (column.SubTasks is not null && column.SubTasks.Length != 0) + { + foreach (SubTask subTask in column.SubTasks) + { + subTasks += 1; + if (subTask.Completed) + completed += 1; + } + } + subtasks = subTasks == 0 ? subtasks = null : $"{completed} / {subTasks}"; + row.Add(new(column.Name, new(tags), subtasks)); + } + } + if (!check) + break; + if (results.Count > 0) + { + if (results[0].Count != row.Count) + throw new Exception("Rows must match!"); + } + results.Add(new(row)); + } + return new(results); + } + + private static void WriteFile(string destinationFile, Heading[] headings, ReadOnlyCollection> recordCollection) + { + string title; + string completed; + List lines = + [ + "", + "", + "", + "", + "", + "" + ]; + foreach (Heading heading in headings) + lines.Add($""); + lines.Add(""); + foreach (ReadOnlyCollection records in recordCollection) + { + lines.Add(""); + foreach (Record record in records) + { + lines.Add(""); + } + lines.Add(""); + } + lines.Add("
{heading.Name}
"); + title = record.Title is null ? " " : record.Title; + completed = record.Completed is null ? " " : record.Completed; + lines.Add($"
{title}
"); + lines.Add("
"); + foreach (string tag in record.Tags) + lines.Add($"{tag}"); + lines.Add("
"); + lines.Add($"
{completed}
"); + lines.Add("
"); + lines.Add(""); + File.WriteAllLines(destinationFile, lines); + } + + private static void ParseKanbn(ILogger logger, string destinationFile, string json) + { + Root? root = JsonSerializer.Deserialize(json, Helper20240822RootSourceGenerationContext.Default.Root); + if (root is null) + logger.LogInformation("<{root}> is null!", root); + else if (root.Lanes.Length != 1) + logger.LogInformation("{root.Lanes} != 1", root.Lanes.Length); + else if (root.Lanes[0].Columns.Length != root.Headings.Length) + logger.LogInformation("{root[0].Columns.Lanes} != {root.Headings}", root.Lanes[0].Columns.Length, root.Headings.Length); + else + { + ReadOnlyCollection> recordCollection = GetRecords(root.Lanes[0].Columns); + WriteFile(destinationFile, root.Headings, recordCollection); + } + } + + internal static void ParseKanbn(ILogger logger, List args) + { + string sourceDirectory = Path.GetFullPath(args[0]); + string sourceFile = Path.Combine(sourceDirectory, args[2]); + string destinationFile = Path.Combine(sourceDirectory, $"{DateTime.Now.Ticks}-{args[3]}"); + if (!File.Exists(sourceFile)) + logger.LogInformation("<{sourceFile}> doesn't exist!", sourceFile); + else + { + string json = File.ReadAllText(sourceFile); + ParseKanbn(logger, destinationFile, json); + } + } + +} \ No newline at end of file diff --git a/Day/Q32024/Helper-2024-08-28.cs b/Day/Q32024/Helper-2024-08-28.cs new file mode 100644 index 0000000..0b56e3e --- /dev/null +++ b/Day/Q32024/Helper-2024-08-28.cs @@ -0,0 +1,169 @@ +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; + +namespace File_Folder_Helper.Day.Q32024; + +internal static partial class Helper20240828 +{ + + public record Record(string? CassetteId, + ReadOnlyCollection? CassetteSegments, + DateTime? Date, + string? Employee, + ReadOnlyCollection? EquipmentSegments, + int I, + string? LastDate, + ReadOnlyCollection>? Matches); + + private static Record GetRecord(int i, string? lastDate, ReadOnlyCollection> matches) + { + Record result; + if (matches.Count != 4 || matches[0].Count != 3 || matches[3].Count != 3) + result = new Record(null, null, null, null, null, i, null, null); + else + { + string[] equipmentSegments = matches[1][2].Split('|'); + if (equipmentSegments.Length != 2) + result = new Record(null, null, null, null, null, i, null, null); + else + { + string[] cassetteIdSegments = matches[3][2].Split('|'); + if (cassetteIdSegments.Length <= 3) + result = new Record(null, null, null, null, null, i, null, null); + else + result = new Record(cassetteIdSegments[2], + new(cassetteIdSegments), + DateTime.Parse(matches[0][0]), + matches[0][1], + new(equipmentSegments), + i, + lastDate, + new(matches)); + } + } + return result; + } + + private static Record GetRecord(string[] lines, int i) + { + Record result; + int ii = i; + string line; + string[] segments; + string? lastDate = null; + List> matches = []; + for (int j = i; j >= 0; j--) + { + ii = j; + line = lines[j]; + segments = line.Split(','); + if (segments.Length < 2) + continue; + lastDate ??= segments[0]; + if (segments[0] != lastDate) + { + lastDate = segments[0]; + break; + } + matches.Add(new(segments)); + } + result = GetRecord(ii + 1, lastDate, new(matches)); + return result; + } + + private static ReadOnlyCollection GetRecords(string logDirectory, string logSearchPattern) + { + List results = []; + Record record; + string[] lines; + string[] logFiles = Directory.GetFiles(logDirectory, logSearchPattern, SearchOption.TopDirectoryOnly); + foreach (string logFile in logFiles) + { + lines = File.ReadAllLines(logFile); + for (int i = lines.Length - 1; i >= 0; i--) + { + record = GetRecord(lines, i); + i = record.I; + if (record.CassetteId is null || record.CassetteSegments is null || record.Date is null || record.Employee is null || record.EquipmentSegments is null) + { + if (i < 4) + break; + continue; + } + results.Add(record); + } + } + return new(results); + } + + private static Dictionary> GetKeyValuePairs(Dictionary> keyValuePairs) + { + Dictionary> results = []; + foreach (KeyValuePair> keyValuePair in keyValuePairs) + results.Add(keyValuePair.Key, new(keyValuePair.Value)); + return new(results); + } + + private static Dictionary> GetKeyValuePairs(string logSearchPattern, string logDirectory) + { + Dictionary> results; + int totalMinutes; + TimeSpan timeSpan; + List? collection; + Dictionary> keyValuePairs = []; + ReadOnlyCollection records = GetRecords(logDirectory, logSearchPattern); + foreach (Record record in records) + { + if (record.CassetteId is null || record.CassetteSegments is null || record.Date is null || record.Employee is null || record.EquipmentSegments is null) + continue; + timeSpan = TimeSpan.FromTicks(record.Date.Value.Ticks); + totalMinutes = (int)Math.Floor(timeSpan.TotalMinutes); + if (!keyValuePairs.TryGetValue(totalMinutes, out collection)) + { + keyValuePairs.Add(totalMinutes, []); + if (!keyValuePairs.TryGetValue(totalMinutes, out collection)) + throw new Exception(); + } + collection.Add(record); + } + results = GetKeyValuePairs(keyValuePairs); + return results; + } + + internal static void MoveWaferCounterToArchive(ILogger logger, List args) + { + int totalMinutes; + string checkFile; + TimeSpan timeSpan; + string? checkDirectory; + string logDateFormat = args[3]; + string wcSearchPattern = args[5]; + string logSearchPattern = args[2]; + ReadOnlyCollection? records; + string logDirectory = Path.GetFullPath(args[0]); + string sourceDirectory = Path.GetFullPath(args[4]); + Dictionary> keyValuePairs = GetKeyValuePairs(logSearchPattern, logDirectory); + logger.LogInformation("Mapped {keyValuePairs}(s)", keyValuePairs.Count); + FileInfo[] collection = Directory.GetFiles(sourceDirectory, wcSearchPattern, SearchOption.AllDirectories).Select(l => new FileInfo(l)).ToArray(); + logger.LogInformation("Found {collection}(s)", collection.Length); + foreach (FileInfo fileInfo in collection) + { + timeSpan = TimeSpan.FromTicks(fileInfo.LastWriteTime.Ticks); + totalMinutes = (int)Math.Floor(timeSpan.TotalMinutes); + if (!keyValuePairs.TryGetValue(totalMinutes, out records)) + continue; + if (records.Count != 1) + continue; + checkDirectory = Path.Combine(logDirectory, timeSpan.ToString(logDateFormat)); + if (string.IsNullOrEmpty(checkDirectory)) + continue; + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + checkFile = Path.Combine(checkDirectory, fileInfo.Name); + if (File.Exists(checkFile)) + continue; + File.Move(fileInfo.FullName, checkFile); + } + } + +} \ No newline at end of file diff --git a/File-Folder-Helper.csproj b/File-Folder-Helper.csproj index ea0b4bc..52bffee 100644 --- a/File-Folder-Helper.csproj +++ b/File-Folder-Helper.csproj @@ -1,4 +1,4 @@ - + enable Exe @@ -16,8 +16,8 @@ - - + +