diff --git a/.gitignore b/.gitignore index 7a8378f..d13d98d 100644 --- a/.gitignore +++ b/.gitignore @@ -335,3 +335,4 @@ ASALocalRun/ .extensions-vscode .extensions-vscode-oss .extensions-vscode-insiders +.vscode/.UserSecrets/secrets.json diff --git a/.vscode/mklink.md b/.vscode/mklink.md index 5aac8e9..c912aaa 100644 --- a/.vscode/mklink.md +++ b/.vscode/mklink.md @@ -18,7 +18,11 @@ mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.kanbn" "D:\5-Other-Small\Kanban del "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" del "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" del "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" -mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.6.2" -mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.6.2" -mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.6.2" +mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.6.3" +mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.6.3" +mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.6.3" +``` + +```bash Thu Jul 18 2024 13:47:40 GMT-0700 (Mountain Standard Time) +mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.vscode\.UserSecrets" "L:\Git\Notes-User-Secrets\.UserSecrets\8da397d4-13ec-4576-9722-3c79cad25563" ``` diff --git a/.vscode/settings.json b/.vscode/settings.json index e6247ad..4b87e1d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -31,6 +31,7 @@ "onenote", "pged", "Phares", + "Reparse", "Rijndael", "Serilog", "SUBM", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5338b78..3489de8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -105,94 +105,50 @@ ], "problemMatcher": "$msCompile" }, - { - "label": "File-Folder-Helper AOT s H Run Data Repository", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository'", - "problemMatcher": [] - }, { "label": "File-Folder-Helper AOT s J Verdaccio", "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s J 'L:/Verdaccio/storage'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s M Self .Kanbn Tasks", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s M L:/DevOps/Mesa_FI/File-Folder-Helper L:/DevOps/Mesa_FI/File-Folder-Helper/.kanbn/tasks", + "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe", + "args": [ + "s", + "J", + "L:/Verdaccio/storage", + ], "problemMatcher": [] }, { "label": "File-Folder-Helper AOT s S BaGet", "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s S 'L:/BaGet/packages'", + "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe", + "args": [ + "s", + "S", + "L:/BaGet/packages", + ], "problemMatcher": [] }, { "label": "File-Folder-Helper AOT s X SortCodeMethods", "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s X L:/DevOps/Mesa_FI/File-Folder-Helper Day-Helper-2024-01-08 L:/DevOps/Mesa_FI/File-Folder-Helper/Day/2024-Q2", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08ANLYSDIFAAST230", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08ANLYSDIFAAST230\\Source\\MET08ANLYSDIFAAST230'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08DDUPSFS6420", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08DDUPSFS6420\\Source\\MET08DDUPSFS6420'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08DDUPSP1TBI", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08DDUPSP1TBI\\Source\\MET08DDUPSP1TBI'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08RESIHGCV", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08RESIHGCV\\Source\\MET08RESIHGCV'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08RESIMAPCDE", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08RESIMAPCDE\\Source\\MET08RESIMAPCDE'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08RESISRP2100", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08RESISRP2100\\Source\\MET08RESISRP2100'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08THFTIRQS408M", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08THFTIRQS408M\\Source\\MET08THFTIRQS408M'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H MET08THFTIRSTRATUS", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\Metrology\\Run Data Repository\\MET08THFTIRSTRATUS\\Source\\MET08THFTIRSTRATUS'", - "problemMatcher": [] - }, - { - "label": "File-Folder-Helper AOT s H WaferCounter", - "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s H '\\\\messa01ec.infineon.com\\apps\\WaferCounter\\BackupFiles'", + "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe", + "args": [ + "s", + "X", + "L:/DevOps/Mesa_FI/File-Folder-Helper", + "Day-Helper-2024-01-08", + "L:/DevOps/Mesa_FI/File-Folder-Helper/Helpers" + ], "problemMatcher": [] }, { "label": "File-Folder-Helper AOT s F Staging _Logs", "type": "shell", - "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe s F '\\\\messv02ecc1.ec.local\\EC_EAFLog\\Staging\\_ Logs'", + "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe", + "args": [ + "s", + "F", + "'\\\\messv02ecc1.ec.local\\EC_EAFLog\\Staging\\_ Logs'", + ], "problemMatcher": [] }, { diff --git a/Day/2024-Q1/Helper-2024-01-06.cs b/Day/2024-Q1/Helper-2024-01-06.cs index b2a34ff..2ddf02d 100644 --- a/Day/2024-Q1/Helper-2024-01-06.cs +++ b/Day/2024-Q1/Helper-2024-01-06.cs @@ -1,3 +1,4 @@ +using File_Folder_Helper.Models; using Microsoft.Extensions.Logging; using System.Collections.ObjectModel; using System.Text; @@ -9,22 +10,6 @@ namespace File_Folder_Helper.Day; internal static partial class Helper20240106 { - private record Host([property: JsonPropertyName("a")] string? Id, - [property: JsonPropertyName("b")] string? Colon, - [property: JsonPropertyName("c")] string? Hyphen, - [property: JsonPropertyName("d")] string? Line, - [property: JsonPropertyName("e")] string? Count, - [property: JsonPropertyName("f")] string? Segments, - [property: JsonPropertyName("g")] string? Type, - [property: JsonPropertyName("h")] string? Device, - [property: JsonPropertyName("i")] string? Name); - - [JsonSourceGenerationOptions(WriteIndented = true, AllowTrailingCommas = true)] - [JsonSerializable(typeof(Host[]))] - private partial class HostSourceGenerationContext : JsonSerializerContext - { - } - private record Record(string Key, Dictionary KeyValuePairs); [JsonSourceGenerationOptions(WriteIndented = true)] diff --git a/Day/2024-Q2/Helper-2024-04-03.cs b/Day/2024-Q2/Helper-2024-04-03.cs index eff0e29..53e5467 100644 --- a/Day/2024-Q2/Helper-2024-04-03.cs +++ b/Day/2024-Q2/Helper-2024-04-03.cs @@ -13,6 +13,40 @@ internal static partial class Helper20240403 string Pattern, string Primary); + private static void AlertIfNewDeviceIsConnected(DynamicHostConfigurationProtocolConfiguration dynamicHostConfigurationProtocolConfiguration, ILogger logger) + { + string[] files = Directory.GetFiles(dynamicHostConfigurationProtocolConfiguration.Directory, dynamicHostConfigurationProtocolConfiguration.Pattern, SearchOption.TopDirectoryOnly); + string? match = GetMatch(dynamicHostConfigurationProtocolConfiguration, files); + if (string.IsNullOrEmpty(match)) + throw new NotSupportedException($"{dynamicHostConfigurationProtocolConfiguration.Primary} doesn't exist!"); + ReadOnlyDictionary keyToCounts = GetKeyToCounts(dynamicHostConfigurationProtocolConfiguration, files); + foreach (KeyValuePair keyToCount in keyToCounts) + { + if (keyToCount.Value < 2) + continue; + logger.LogInformation("{Key}: {Count}", keyToCount.Key, keyToCount.Value); + } + ReadOnlyDictionary>> keyValuePairs = GetKeyValuePairs(dynamicHostConfigurationProtocolConfiguration, files); + foreach (KeyValuePair>> keyValuePair in keyValuePairs) + { + if (!keyValuePair.Key.EndsWith(dynamicHostConfigurationProtocolConfiguration.Primary)) + continue; + } + } + + internal static void AlertIfNewDeviceIsConnected(ILogger logger, List args) + { + string ignore = args[6]; + string pattern = args[2]; + string primary = args[3]; + string keyIndex = args[5]; + string directory = args[0]; + logger.LogInformation(directory); + string[] columns = args[4].Split('|'); + DynamicHostConfigurationProtocolConfiguration dynamicHostConfigurationProtocolConfiguration = new(columns, directory, ignore, int.Parse(keyIndex), pattern, primary); + AlertIfNewDeviceIsConnected(dynamicHostConfigurationProtocolConfiguration, logger); + } + private static string? GetMatch(DynamicHostConfigurationProtocolConfiguration dynamicHostConfigurationProtocolConfiguration, string[] files) { string? result = null; @@ -114,38 +148,4 @@ internal static partial class Helper20240403 return results; } - private static void AlertIfNewDeviceIsConnected(DynamicHostConfigurationProtocolConfiguration dynamicHostConfigurationProtocolConfiguration, ILogger logger) - { - string[] files = Directory.GetFiles(dynamicHostConfigurationProtocolConfiguration.Directory, dynamicHostConfigurationProtocolConfiguration.Pattern, SearchOption.TopDirectoryOnly); - string? match = GetMatch(dynamicHostConfigurationProtocolConfiguration, files); - if (string.IsNullOrEmpty(match)) - throw new NotSupportedException($"{dynamicHostConfigurationProtocolConfiguration.Primary} doesn't exist!"); - ReadOnlyDictionary keyToCounts = GetKeyToCounts(dynamicHostConfigurationProtocolConfiguration, files); - foreach (KeyValuePair keyToCount in keyToCounts) - { - if (keyToCount.Value < 2) - continue; - logger.LogInformation("{Key}: {Count}", keyToCount.Key, keyToCount.Value); - } - ReadOnlyDictionary>> keyValuePairs = GetKeyValuePairs(dynamicHostConfigurationProtocolConfiguration, files); - foreach (KeyValuePair>> keyValuePair in keyValuePairs) - { - if (!keyValuePair.Key.EndsWith(dynamicHostConfigurationProtocolConfiguration.Primary)) - continue; - } - } - - internal static void AlertIfNewDeviceIsConnected(ILogger logger, List args) - { - string ignore = args[6]; - string pattern = args[2]; - string primary = args[3]; - string keyIndex = args[5]; - string directory = args[0]; - logger.LogInformation(directory); - string[] columns = args[4].Split('|'); - DynamicHostConfigurationProtocolConfiguration dynamicHostConfigurationProtocolConfiguration = new(columns, directory, ignore, int.Parse(keyIndex), pattern, primary); - AlertIfNewDeviceIsConnected(dynamicHostConfigurationProtocolConfiguration, logger); - } - } \ No newline at end of file diff --git a/Day/2024-Q2/Helper-2024-04-04.cs b/Day/2024-Q2/Helper-2024-04-04.cs index 699bcb6..3047242 100644 --- a/Day/2024-Q2/Helper-2024-04-04.cs +++ b/Day/2024-Q2/Helper-2024-04-04.cs @@ -21,27 +21,6 @@ internal static partial class Helper20240404 string RegularExpressionPattern, string SearchPattern); - private static MetaData? GetMetaData(CommaSeparatedValuesConfiguration commaSeparatedValuesConfiguration, string fileNameWithoutExtension) - { - MetaData? result; - Match match = Regex.Match(fileNameWithoutExtension, commaSeparatedValuesConfiguration.RegularExpressionPattern); - if (!match.Success || match.Groups.Count != commaSeparatedValuesConfiguration.RegularExpressionGroupCount) - result = null; - else - { - int deviceId = int.Parse(match.Groups["DeviceId"].Value); - int deviceNumber = int.Parse(match.Groups["DeviceNumber"].Value); - result = new(deviceId, - match.Groups["DeviceType"].Value, - deviceNumber, - match.Groups["DescriptionName"].Value, - match.Groups["DescriptionTest"].Value, - match.Groups["Frequency"].Value, - match.Groups["Date"].Value); - } - return result; - } - private static void ParseCSV(CommaSeparatedValuesConfiguration commaSeparatedValuesConfiguration, ILogger logger) { string line; @@ -93,4 +72,25 @@ internal static partial class Helper20240404 ParseCSV(commaSeparatedValuesConfiguration, logger); } + private static MetaData? GetMetaData(CommaSeparatedValuesConfiguration commaSeparatedValuesConfiguration, string fileNameWithoutExtension) + { + MetaData? result; + Match match = Regex.Match(fileNameWithoutExtension, commaSeparatedValuesConfiguration.RegularExpressionPattern); + if (!match.Success || match.Groups.Count != commaSeparatedValuesConfiguration.RegularExpressionGroupCount) + result = null; + else + { + int deviceId = int.Parse(match.Groups["DeviceId"].Value); + int deviceNumber = int.Parse(match.Groups["DeviceNumber"].Value); + result = new(deviceId, + match.Groups["DeviceType"].Value, + deviceNumber, + match.Groups["DescriptionName"].Value, + match.Groups["DescriptionTest"].Value, + match.Groups["Frequency"].Value, + match.Groups["Date"].Value); + } + return result; + } + } \ No newline at end of file diff --git a/Day/2024-Q2/Helper-2024-05-17.cs b/Day/2024-Q2/Helper-2024-05-17.cs index 8892f3c..0173bf3 100644 --- a/Day/2024-Q2/Helper-2024-05-17.cs +++ b/Day/2024-Q2/Helper-2024-05-17.cs @@ -236,40 +236,6 @@ internal static partial class Helper20240517 { } - private static ReadOnlyCollection<(string, string)> GetAggregationLines(string harFile) - { - List<(string, string)> results = []; - if (!File.Exists(harFile)) - throw new Exception(); - string lastUrl = string.Empty; - string text = "\"text\": \"{"; - string[] lines = File.ReadAllLines(harFile); - foreach (string line in lines) - { - if (line.Contains("\"url\": \"")) - lastUrl = line; - if (!line.Contains(text)) - continue; - if (!line.Contains("aggregations")) - continue; - if (lastUrl.Contains("search?asset=NONE")) - continue; - results.Add(new(lastUrl, line.Trim()[(text.Length - 1)..^1].Replace("\\\"", "\""))); - lastUrl = string.Empty; - } - return new(results); - } - - private static void SaveAmazon(IReadOnlyList data, string personIdFile) - { - string json; - Dictionary keyValuePairs = []; - foreach (Datum datum in data) - _ = keyValuePairs.TryAdd(datum.Name.Split('.')[0], datum); - json = JsonSerializer.Serialize(keyValuePairs, DictionaryDatumGenerationContext.Default.DictionaryStringDatum); - File.WriteAllText(personIdFile, json); - } - private static void SaveAmazon(string destination, string harFile) { string offset; @@ -331,4 +297,38 @@ internal static partial class Helper20240517 logger?.LogInformation("{harFiles} count", harFiles.Length); } + private static void SaveAmazon(IReadOnlyList data, string personIdFile) + { + string json; + Dictionary keyValuePairs = []; + foreach (Datum datum in data) + _ = keyValuePairs.TryAdd(datum.Name.Split('.')[0], datum); + json = JsonSerializer.Serialize(keyValuePairs, DictionaryDatumGenerationContext.Default.DictionaryStringDatum); + File.WriteAllText(personIdFile, json); + } + + private static ReadOnlyCollection<(string, string)> GetAggregationLines(string harFile) + { + List<(string, string)> results = []; + if (!File.Exists(harFile)) + throw new Exception(); + string lastUrl = string.Empty; + string text = "\"text\": \"{"; + string[] lines = File.ReadAllLines(harFile); + foreach (string line in lines) + { + if (line.Contains("\"url\": \"")) + lastUrl = line; + if (!line.Contains(text)) + continue; + if (!line.Contains("aggregations")) + continue; + if (lastUrl.Contains("search?asset=NONE")) + continue; + results.Add(new(lastUrl, line.Trim()[(text.Length - 1)..^1].Replace("\\\"", "\""))); + lastUrl = string.Empty; + } + return new(results); + } + } \ No newline at end of file diff --git a/Day/2024-Q2/Helper-2024-06-23.cs b/Day/2024-Q2/Helper-2024-06-23.cs index c2783d3..527a8f6 100644 --- a/Day/2024-Q2/Helper-2024-06-23.cs +++ b/Day/2024-Q2/Helper-2024-06-23.cs @@ -1,19 +1,21 @@ using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; namespace File_Folder_Helper.Day; internal static partial class Helper20240623 { + private record SubTaskLine(string Text, bool Done, long? Ticks, int? Line); private record Record(int? CodeInsidersLine, string File, string[] Lines, int? StopLine, int? SubTasksLine); private static List GetRecords(string sourceDirectory, string searchPattern, string codeInsiders, string subTasks) { List results = []; int? stopLine; + string[] lines; int? subTasksLine; int? codeInsidersLine; - string[] lines; string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories); foreach (string file in files) { @@ -52,24 +54,60 @@ internal static partial class Helper20240623 return results; } + private static ReadOnlyCollection GetSubTasks(string subTasks, string[] tasks, bool? foundDone, string fallbackLine, FileInfo fileInfo) + { + List results = []; + string line; + bool doneValue; + string? h1 = null; + bool foundSubTasks = false; + int tasksZeroLength = tasks[0].Length; + string[] lines = File.ReadAllLines(fileInfo.FullName); + for (int i = 0; i < lines.Length; i++) + { + line = lines[i]; + if (line.StartsWith("# ")) + h1 = line[2..]; + if (!foundSubTasks && line == subTasks) + foundSubTasks = true; + if (!foundSubTasks) + continue; + if (line.Length <= tasksZeroLength || !line.StartsWith(tasks[0]) || line[tasksZeroLength] is not ' ' and not 'x' || line[tasksZeroLength + 1] != ']') + continue; + doneValue = foundDone is not null && foundDone.Value; + results.Add(new($" {line}", doneValue, fileInfo.LastWriteTime.Ticks, i)); + } + doneValue = foundDone is not null && foundDone.Value; + if (h1 is null) + results.Add(new(fallbackLine, doneValue, fileInfo.LastWriteTime.Ticks, Line: null)); + else + results.Add(new(foundDone is null || !foundDone.Value ? $"- [ ] {fileInfo.LastWriteTime.Ticks} ~~~ {h1}" : $"- [x] {fileInfo.LastWriteTime.Ticks} ~~~ {h1}", doneValue, fileInfo.LastWriteTime.Ticks, Line: 0)); + return new(results); + } + internal static void UpdateSubTasksInMarkdownFiles(ILogger logger, List args) { int lineCheck; + bool doneValue; bool? foundDone; + FileInfo fileInfo; + string[] newLines; string[] segments; List lines; + string fallbackLine; string[] indexLines; string checkDirectory; string done = args[7]; List indexFiles; string subTasks = args[3]; - List newLines = []; List oldLines = []; string indexFile = args[5]; string searchPattern = args[2]; string directoryFilter = args[8]; string[] tasks = args[6].Split(','); string codeInsiders = $"{args[4]} \""; + List allSubTaskLines = []; + ReadOnlyCollection subTaskLines; string sourceDirectory = Path.GetFullPath(args[0]); List records = GetRecords(sourceDirectory, searchPattern, codeInsiders, subTasks); foreach (Record record in from l in records orderby l.SubTasksLine is null, l.CodeInsidersLine is null select l) @@ -106,36 +144,47 @@ internal static partial class Helper20240623 } } foundDone = null; - newLines.Clear(); oldLines.Clear(); + allSubTaskLines.Clear(); indexLines = File.ReadAllLines(indexFiles[0]); + checkDirectory = Path.GetDirectoryName(indexFiles[0]) ?? throw new Exception(); for (int i = 0; i < indexLines.Length; i++) { if (indexLines[i] == done) foundDone = true; segments = indexLines[i].Split(tasks[1]); + doneValue = foundDone is not null && foundDone.Value; if (segments.Length > 2 || !segments[0].StartsWith(tasks[0])) continue; - if (foundDone is null || !foundDone.Value) - newLines.Add($"- [ ] {segments[0][tasks[0].Length..]}"); - else - newLines.Add($"- [x] {segments[0][tasks[0].Length..]}"); + fallbackLine = foundDone is null || !foundDone.Value ? $"- [ ] {segments[0][tasks[0].Length..]}" : $"- [x] {segments[0][tasks[0].Length..]}"; + fileInfo = new(Path.GetFullPath(Path.Combine(checkDirectory, segments[1][..^1]))); + if (!fileInfo.Exists) + { + allSubTaskLines.Add(new(fallbackLine, doneValue, Ticks: null, Line: null)); + continue; + } + subTaskLines = GetSubTasks(subTasks, tasks, doneValue, fallbackLine, fileInfo); + for (int j = subTaskLines.Count - 1; j >= 0; j--) + allSubTaskLines.Add(subTaskLines[j]); } - if (newLines.Count == 0) + if (allSubTaskLines.Count == 0) continue; lineCheck = 0; - newLines.Insert(0, string.Empty); for (int i = record.SubTasksLine.Value + 1; i < record.StopLine.Value - 1; i++) oldLines.Add(record.Lines[i]); - if (newLines.Count == oldLines.Count) + if (allSubTaskLines.Any(l => l.Ticks is null)) + newLines = (from l in allSubTaskLines select l.Text).ToArray(); + else + newLines = (from l in allSubTaskLines orderby l.Done descending, l.Ticks, l.Line select l.Text).ToArray(); + if (newLines.Length == oldLines.Count) { - for (int i = 0; i < newLines.Count; i++) + for (int i = 0; i < newLines.Length; i++) { if (newLines[i] != record.Lines[record.SubTasksLine.Value + 1 + i]) continue; lineCheck++; } - if (lineCheck == newLines.Count) + if (lineCheck == newLines.Length) continue; } checkDirectory = Path.Combine(checkDirectory, DateTime.Now.Ticks.ToString()); @@ -147,8 +196,9 @@ internal static partial class Helper20240623 lines.RemoveAt(i); if (record.StopLine.Value == record.Lines.Length && lines[^1].Length == 0) lines.RemoveAt(lines.Count - 1); - for (int i = 0; i < newLines.Count; i++) + for (int i = 0; i < newLines.Length; i++) lines.Insert(record.SubTasksLine.Value + 1 + i, newLines[i]); + lines.Insert(record.SubTasksLine.Value + 1, string.Empty); File.WriteAllLines(record.File, lines); } } diff --git a/Day/2024-Q2/Helper-2024-06-24.cs b/Day/2024-Q2/Helper-2024-06-24.cs index be07682..61e85e8 100644 --- a/Day/2024-Q2/Helper-2024-06-24.cs +++ b/Day/2024-Q2/Helper-2024-06-24.cs @@ -73,7 +73,7 @@ internal static partial class Helper20240624 } } - internal static void MoveUpOndDirectory(ILogger logger, List args) + internal static void MoveUpOneDirectory(ILogger logger, List args) { string searchPattern = args[2]; string sourceDirectory = Path.GetFullPath(args[0]); diff --git a/Day/2024-Q3/Helper-2024-07-11.cs b/Day/2024-Q3/Helper-2024-07-11.cs new file mode 100644 index 0000000..3203a86 --- /dev/null +++ b/Day/2024-Q3/Helper-2024-07-11.cs @@ -0,0 +1,79 @@ +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; + +namespace File_Folder_Helper.Day; + +internal static partial class Helper20240711 +{ + + internal static void GitRemoteRemove(ILogger logger, List args) + { + string line; + string[] lines; + bool branchCheck; + bool remoteCheck; + string? directory; + string? parentDirectory; + string parentDirectoryName; + string branchName = args[8]; + string searchPattern = args[2]; + string remoteToAddUrl = args[6]; + string remoteToRemove = args[3]; + string remoteToAddName = args[5]; + ReadOnlyCollection messages; + string remoteToRemoveFilter = args[4]; + string sourceDirectory = Path.GetFullPath(args[0]); + string lastRemoteSegment = remoteToRemove.Split('/')[^1]; + string extension = args[7].Length > 2 ? args[7] : string.Empty; + string[] files = Directory.EnumerateFiles(sourceDirectory, searchPattern, new EnumerationOptions() { IgnoreInaccessible = true, RecurseSubdirectories = true, AttributesToSkip = FileAttributes.None }).ToArray(); + logger.LogInformation("Found {files} file(s)", files.Length); + foreach (string file in files) + { + branchCheck = false; + remoteCheck = false; + lines = File.ReadAllLines(file); + for (int i = 0; i < lines.Length; i++) + { + line = lines[i]; + if (!line.Contains(remoteToRemove)) + continue; + if (!lines[i - 1].Contains(remoteToRemoveFilter)) + continue; + remoteCheck = true; + break; + } + for (int i = 0; i < lines.Length; i++) + { + line = lines[i]; + if (!line.Contains(branchName)) + continue; + branchCheck = true; + break; + } + if (!remoteCheck) + continue; + directory = Path.GetDirectoryName(file); + if (directory is null) + continue; + parentDirectory = Path.GetDirectoryName(directory); + if (parentDirectory is null) + continue; + parentDirectoryName = Path.GetFileName(parentDirectory).ToLower(); + messages = Helpers.HelperGit.RemoteRemove(parentDirectory, lastRemoteSegment, CancellationToken.None); + foreach (string message in messages) + logger.LogInformation("{function} => {parentDirectoryName}: [{message}]", nameof(Helpers.HelperGit.RemoteRemove), parentDirectoryName, message); + messages = Helpers.HelperGit.RemoteAdd(parentDirectory, remoteToAddName, $"{remoteToAddUrl}{parentDirectoryName}{extension}", CancellationToken.None); + foreach (string message in messages) + logger.LogInformation("{function} => {parentDirectoryName}: [{message}]", nameof(Helpers.HelperGit.RemoteAdd), parentDirectoryName, message); + if (!branchCheck) + continue; + try + { messages = Helpers.HelperGit.PushBranch(parentDirectory, remoteToAddName, branchName, CancellationToken.None); } + catch (Exception ex) + { messages = new([ex.Message]); } + foreach (string message in messages) + logger.LogInformation("{function} => {parentDirectoryName}: [{message}]", nameof(Helpers.HelperGit.PushBranch), parentDirectoryName, message); + } + } + +} \ No newline at end of file diff --git a/Day/2024-Q3/Helper-2024-07-18.cs b/Day/2024-Q3/Helper-2024-07-18.cs new file mode 100644 index 0000000..85e6b6f --- /dev/null +++ b/Day/2024-Q3/Helper-2024-07-18.cs @@ -0,0 +1,84 @@ +using File_Folder_Helper.Models; +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; +using System.Text.Json; + +namespace File_Folder_Helper.Day; + +internal static partial class Helper20240718 +{ + + private static Host[] GetHosts(ILogger logger, string file) + { + Host[] results; + string lines = File.ReadAllText(file); + string json = $"[{lines.Replace("\r\n", ",")}]"; + logger.LogDebug(lines); + results = JsonSerializer.Deserialize(json, HostSourceGenerationContext.Default.HostArray) ?? throw new NullReferenceException(); + return results; + } + + private static ReadOnlyCollection GetLines(Host[] hosts, string title, string wired) + { + List results = [$"# {title}", string.Empty, "```mermaid", "flowchart TB", $" subgraph {title}"]; + int id; + string check; + List distinct = []; + string newLine = $"{Environment.NewLine} "; + foreach (Host host in hosts) + { + if (host.Id is null || host.Hyphen is null || host.Device is null || host.Name is null || host.Hyphen.Length != 17) + continue; + if (!int.TryParse(host.Id, out id)) + throw new NotSupportedException($"{host.Id} is not a number"); + if (distinct.Contains(id)) + throw new NotSupportedException($"{id} is not distinct!"); + distinct.Add(id); + results.Add($" {id}(fa:{host.Type}{newLine}{host.Colon}{newLine}{host.Hyphen}{newLine}{host.Device}{newLine}https://{host.Name}/)"); + } + results.Add(" end"); + results.Add($" subgraph {title}"); + foreach (Host host in from l in hosts orderby l.Location, l.Type, l.Line select l) + { + if (host.Id is null || host.Hyphen is null || host.Device is null || host.Name is null || host.Hyphen.Length != 17) + continue; + if (!int.TryParse(host.Id, out id)) + throw new NotSupportedException($"{host.Id} is not a number"); + check = host.Type == wired ? "-->" : "-.->"; + results.Add($" {id} {check} |{id}| {host.Location}{host.Type}{host.Line}"); + } + results.Add(" end"); + results.Add($" subgraph {title}"); + foreach (Host host in from l in hosts orderby l.Line, l.Location, l.Type select l) + { + if (host.Id is null || host.Hyphen is null || host.Device is null || host.Name is null || host.Line is null || host.Hyphen.Length != 17) + continue; + if (!int.TryParse(host.Id, out id)) + throw new NotSupportedException($"{host.Id} is not a number"); + check = host.Type == wired ? "-->" : "-.->"; + results.Add($" {host.Location}{host.Type}{host.Line} {check} Line{host.Line}"); + } + results.Add(" end"); + results.Add("```"); + return results.AsReadOnly(); + } + + internal static void JsonToMarkdown(ILogger logger, List args) + { + Host[] hosts; + string title = args[3]; + string wired = args[4]; + string extension = args[5]; + string searchPattern = args[2]; + ReadOnlyCollection lines; + string sourceDirectory = Path.GetFullPath(args[0]); + string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.TopDirectoryOnly); + foreach (string file in files) + { + hosts = GetHosts(logger, file); + lines = GetLines(hosts, title, wired); + File.WriteAllText($"{file}{extension}", string.Join(Environment.NewLine, lines)); + } + } + +} \ No newline at end of file diff --git a/Day/2024-Q3/Helper-2024-07-24.cs b/Day/2024-Q3/Helper-2024-07-24.cs new file mode 100644 index 0000000..222800d --- /dev/null +++ b/Day/2024-Q3/Helper-2024-07-24.cs @@ -0,0 +1,206 @@ +using File_Folder_Helper.Models; +using Microsoft.Extensions.Logging; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; +using System.Text.Json; + +namespace File_Folder_Helper.Day; + +internal static partial class Helper20240724 +{ + + private record FileConnectorConfigurationSystem(string AlternateTargetFolder, + string FileAgeThreshold, + string[] SourceFileFilters, + string TargetFileLocation); + +#pragma warning disable IDE0028, IDE0056, IDE0300, IDE0240, IDE0241 + + private static readonly HttpClient _HttpClient = new(); + private static readonly string _StaticFileServer = "localhost:5054"; + private static readonly FileConnectorConfigurationSystem _FileConnectorConfiguration = new( + "D:/Tmp/Phares/AlternateTargetFolder", + "000:20:00:01", + [".txt"], + "D:/Tmp/Phares/TargetFileLocation"); + + private static DateTime GetFileAgeThresholdDateTime(string fileAgeThreshold) + { + DateTime result = DateTime.Now; + string[] segments = fileAgeThreshold.Split(':'); + for (int i = 0; i < segments.Length; i++) + { + result = i switch + { + 0 => result.AddDays(double.Parse(segments[i]) * -1), + 1 => result.AddHours(double.Parse(segments[i]) * -1), + 2 => result.AddMinutes(double.Parse(segments[i]) * -1), + 3 => result.AddSeconds(double.Parse(segments[i]) * -1), + _ => throw new Exception(), + }; + } + return result; + } + + private static string[] GetValidWeeks(DateTime fileAgeThresholdDateTime) + { + DateTime dateTime = DateTime.Now; + Calendar calendar = new CultureInfo("en-US").Calendar; + string weekOfYear = $"{dateTime:yyyy}_Week_{calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}"; + string lastWeekOfYear = $"{fileAgeThresholdDateTime:yyyy}_Week_{calendar.GetWeekOfYear(fileAgeThresholdDateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}"; + return new string[] { weekOfYear, lastWeekOfYear }.Distinct().ToArray(); + } + + private static string[] GetValidDays(DateTime fileAgeThresholdDateTime) + { + DateTime dateTime = DateTime.Now; + return new string[] { dateTime.ToString("yyyy-MM-dd"), fileAgeThresholdDateTime.ToString("yyyy-MM-dd") }.Distinct().ToArray(); + } + + private static ReadOnlyCollection GetDayNginxFileSystemCollection(DateTime fileAgeThresholdDateTime, string week, string day, string dayUrl, NginxFileSystem[] dayNginxFileSystemCollection) + { + List results = new(); + DateTime dateTime; + string nginxFormat = "ddd, dd MMM yyyy HH:mm:ss zzz"; + foreach (NginxFileSystem dayNginxFileSystem in dayNginxFileSystemCollection) + { + if (!DateTime.TryParseExact(dayNginxFileSystem.MTime.Replace("GMT", "+00:00"), nginxFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) + continue; + if (dateTime < fileAgeThresholdDateTime) + continue; + results.Add(new( + Path.GetFullPath(Path.Combine(_FileConnectorConfiguration.TargetFileLocation, week, day, dayNginxFileSystem.Name)), + string.Concat(dayUrl, '/', dayNginxFileSystem.Name), + dateTime.ToString(), + dayNginxFileSystem.Size)); + } + return results.AsReadOnly(); + } + + private static ReadOnlyCollection GetDayNginxFileSystemCollection(DateTime fileAgeThresholdDateTime) + { +#nullable enable + List results = new(); + string dayUrl; + string dayJson; + string weekJson; + string checkWeek; + Task task; + NginxFileSystem[]? dayNginxFileSystemCollection; + NginxFileSystem[]? weekNginxFileSystemCollection; + string[] days = GetValidDays(fileAgeThresholdDateTime); + string[] weeks = GetValidWeeks(fileAgeThresholdDateTime); + foreach (string week in weeks) + { + checkWeek = string.Concat("http://", _StaticFileServer, '/', week); + task = _HttpClient.GetAsync(checkWeek); + task.Wait(); + if (!task.Result.IsSuccessStatusCode) + continue; + weekJson = _HttpClient.GetStringAsync(checkWeek).Result; + weekNginxFileSystemCollection = JsonSerializer.Deserialize(weekJson, NginxFileSystemCollectionSourceGenerationContext.Default.NginxFileSystemArray); + if (weekNginxFileSystemCollection is null) + continue; + foreach (NginxFileSystem weekNginxFileSystem in weekNginxFileSystemCollection) + { + if (!(from l in days where weekNginxFileSystem.Name == l select false).Any()) + continue; + dayUrl = string.Concat(checkWeek, '/', weekNginxFileSystem.Name); + dayJson = _HttpClient.GetStringAsync(dayUrl).Result; + dayNginxFileSystemCollection = JsonSerializer.Deserialize(dayJson, NginxFileSystemCollectionSourceGenerationContext.Default.NginxFileSystemArray); + if (dayNginxFileSystemCollection is null) + continue; + results.AddRange(GetDayNginxFileSystemCollection(fileAgeThresholdDateTime, week, weekNginxFileSystem.Name, dayUrl, dayNginxFileSystemCollection)); + } + } + return results.AsReadOnly(); +#nullable disable + } + + private static ReadOnlyCollection> GetPossible() + { + List> results = new(); + DateTime dateTime; + FileInfo targetFileInfo; + FileInfo alternateFileInfo; + DateTime fileAgeThresholdDateTime = GetFileAgeThresholdDateTime(_FileConnectorConfiguration.FileAgeThreshold); + ReadOnlyCollection dayNginxFileSystemCollection = GetDayNginxFileSystemCollection(fileAgeThresholdDateTime); + foreach (NginxFileSystem nginxFileSystem in dayNginxFileSystemCollection) + { + targetFileInfo = new FileInfo(nginxFileSystem.Name); + if (targetFileInfo.Directory is null) + continue; + if (!Directory.Exists(targetFileInfo.Directory.FullName)) + _ = Directory.CreateDirectory(targetFileInfo.Directory.FullName); + if (!DateTime.TryParse(nginxFileSystem.MTime, out dateTime)) + continue; + if (targetFileInfo.Exists && targetFileInfo.LastWriteTime == dateTime) + continue; + alternateFileInfo = new(Path.Combine(_FileConnectorConfiguration.AlternateTargetFolder, nginxFileSystem.Name)); + results.Add(new(dateTime, targetFileInfo, alternateFileInfo, nginxFileSystem.Type)); + } + return (from l in results orderby l.Item1 select l).ToList().AsReadOnly(); + } + + private static void Test() + { +#nullable enable + if (_HttpClient is null) + throw new Exception(); + if (string.IsNullOrEmpty(_StaticFileServer)) + throw new Exception(); + if (string.IsNullOrEmpty(_StaticFileServer)) + { + ReadOnlyCollection> possibleDownload = GetPossible(); + if (possibleDownload.Count > 0) + { + string targetFileName = possibleDownload[0].Item4; + FileInfo targetFileInfo = possibleDownload[0].Item2; + FileInfo alternateFileInfo = possibleDownload[0].Item3; + DateTime matchNginxFileSystemDateTime = possibleDownload[0].Item1; + // if (alternateFileInfo.Exists) + // File.Delete(alternateFileInfo.FullName); + if (targetFileInfo.Exists) + File.Delete(targetFileInfo.FullName); + string targetJson = _HttpClient.GetStringAsync(targetFileName).Result; + File.WriteAllText(targetFileInfo.FullName, targetJson); + targetFileInfo.LastWriteTime = matchNginxFileSystemDateTime; + // File.Copy(targetFileInfo.FullName, alternateFileInfo.FullName); + File.AppendAllText(alternateFileInfo.FullName, targetJson); + } + } +#nullable disable + } + + internal static void CopyDirectories(ILogger logger, List args) + { + Test(); + string[] files; + Process process; + string checkDirectory; + string filter = args[3]; + string replaceWith = args[4]; + string searchPattern = args[2]; + string sourceDirectory = Path.GetFullPath(args[0]); + string[] foundDirectories = Directory.GetDirectories(sourceDirectory, searchPattern, SearchOption.AllDirectories); + logger.LogInformation($"Found {foundDirectories.Length} directories"); + foreach (string foundDirectory in foundDirectories) + { + if (!foundDirectory.Contains(filter)) + continue; + logger.LogDebug(foundDirectory); + checkDirectory = foundDirectory.Replace(filter, replaceWith); + if (Directory.Exists(checkDirectory)) + { + files = Directory.GetFiles(checkDirectory, "*", SearchOption.AllDirectories); + if (files.Length > 0) + continue; + Directory.Delete(checkDirectory); + } + process = Process.Start("cmd.exe", $"/c xCopy \"{foundDirectory}\" \"{checkDirectory}\" /S /E /I /H /Y"); + process.WaitForExit(); + } + } + +} \ No newline at end of file diff --git a/Day/2024-Q3/Helper-2024-07-28.cs b/Day/2024-Q3/Helper-2024-07-28.cs new file mode 100644 index 0000000..b78b930 --- /dev/null +++ b/Day/2024-Q3/Helper-2024-07-28.cs @@ -0,0 +1,64 @@ +using Microsoft.Extensions.Logging; +using System.Diagnostics; + +namespace File_Folder_Helper.Day; + +internal static partial class Helper20240728 +{ + + internal static void DownloadSslCertificates(ILogger logger, List args) + { + string file; + Process? process; + string[] segments; + string standardError; + string standardOutput; + string argumentSegment; + string store = args[9]; + string domain = args[2]; + List lines = []; + string logSegment = args[8]; + string endCertificate = args[7]; + string beginCertificate = args[6]; + int waitForExit = int.Parse(args[5]); + string[] subdomains = args[3].Split(','); + string sourceDirectory = Path.GetFullPath(args[0]); + ProcessStartInfo processStartInfo = new() + { + CreateNoWindow = true, + RedirectStandardError = true, + RedirectStandardOutput = true, + UseShellExecute = false, + FileName = args[4], + WorkingDirectory = sourceDirectory + }; + foreach (string subdomain in subdomains) + { + argumentSegment = $"{subdomain}.{domain}:443 -servername {subdomain}.{domain}"; + processStartInfo.Arguments = $"s_client -connect {subdomain}.{domain}:443 -servername {subdomain}.{domain}"; + process = Process.Start(processStartInfo); + if (process is null) + continue; + _ = process.WaitForExit(waitForExit); + process.Kill(entireProcessTree: true); + standardOutput = process.StandardOutput.ReadToEnd(); + if (!standardOutput.Contains(beginCertificate) || !standardOutput.Contains(endCertificate)) + { + standardError = process.StandardError.ReadToEnd(); + logger.LogWarning($"Error: {subdomain}{Environment.NewLine}{standardOutput}{Environment.NewLine}{standardError}"); + continue; + } + segments = standardOutput.Split(beginCertificate); + if (segments.Length != 2) + break; + segments = segments[1].Split(endCertificate); + if (segments.Length != 2) + break; + lines.Add($"{logSegment} \"{store}\" {subdomain}.{domain}.cert"); + file = Path.Combine(sourceDirectory, $"{subdomain}.{domain}.cert"); + File.WriteAllText(file, $"{beginCertificate}{segments[0]}{endCertificate}{Environment.NewLine}"); + } + File.WriteAllLines(Path.Combine(sourceDirectory, $"{DateTime.Now.Ticks}.txt"), lines); + } + +} \ No newline at end of file diff --git a/Day/HelperDay.cs b/Day/HelperDay.cs index e31269d..b5cfbe4 100644 --- a/Day/HelperDay.cs +++ b/Day/HelperDay.cs @@ -76,7 +76,15 @@ internal static class HelperDay else if (args[1] == "Day-Helper-2024-06-23") Day.Helper20240623.UpdateSubTasksInMarkdownFiles(logger, args); else if (args[1] == "Day-Helper-2024-06-24") - Day.Helper20240624.MoveUpOndDirectory(logger, args); + Day.Helper20240624.MoveUpOneDirectory(logger, args); + else if (args[1] == "Day-Helper-2024-07-11") + Day.Helper20240711.GitRemoteRemove(logger, args); + else if (args[1] == "Day-Helper-2024-07-18") + Day.Helper20240718.JsonToMarkdown(logger, args); + else if (args[1] == "Day-Helper-2024-07-24") + Day.Helper20240724.CopyDirectories(logger, args); + else if (args[1] == "Day-Helper-2024-07-28") + Day.Helper20240728.DownloadSslCertificates(logger, args); else throw new Exception(appSettings.Company); } diff --git a/File-Folder-Helper.csproj b/File-Folder-Helper.csproj index 9e09365..f90af22 100644 --- a/File-Folder-Helper.csproj +++ b/File-Folder-Helper.csproj @@ -16,10 +16,10 @@ - - + + - + \ No newline at end of file diff --git a/Helpers/HelperGit.cs b/Helpers/HelperGit.cs index c7a1e1b..4f3b92b 100644 --- a/Helpers/HelperGit.cs +++ b/Helpers/HelperGit.cs @@ -43,24 +43,78 @@ internal static class HelperGit return result.Output; } + private static List GetOthersModifiedAndDeletedExcludingStandardFilesAsList(string repositoryDirectory, bool usePathCombine, CancellationToken cancellationToken) + { + List results = []; + Task task = RunAsync("ls-files --others --modified --deleted --exclude-standard", repositoryDirectory, cancellationToken); + task.Wait(cancellationToken); + string[] files = task.Result.Split("\r\n"); + foreach (string file in files) + { + if (!usePathCombine) + results.Add(file); + else + results.Add(Path.GetFullPath(Path.Combine(repositoryDirectory, file))); + } + return results; + } + internal static ReadOnlyCollection GetOthersModifiedAndDeletedExcludingStandardFiles(string repositoryDirectory, bool usePathCombine, CancellationToken cancellationToken) { List results = []; + List relativePathFiles; + DirectoryInfo directoryInfo; + bool usePathCombineInner = false; string checkDirectory = Path.Combine(repositoryDirectory, ".git"); if (Directory.Exists(checkDirectory)) + results.AddRange(GetOthersModifiedAndDeletedExcludingStandardFilesAsList(repositoryDirectory, usePathCombine, cancellationToken)); + string[] subdirectories = Directory.GetDirectories(repositoryDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string subdirectory in subdirectories) { - Task task = RunAsync($"ls-files --others --modified --deleted --exclude-standard", repositoryDirectory, cancellationToken); - task.Wait(cancellationToken); - string[] files = task.Result.Split("\r\n"); - foreach (string file in files) - { - if (!usePathCombine) - results.Add(file); - else - results.Add(Path.GetFullPath(Path.Combine(repositoryDirectory, file))); - } + directoryInfo = new(subdirectory); + if (directoryInfo.LinkTarget is null) + continue; + checkDirectory = Path.Combine(directoryInfo.LinkTarget, ".git"); + if (!Directory.Exists(checkDirectory)) + continue; + relativePathFiles = GetOthersModifiedAndDeletedExcludingStandardFilesAsList(directoryInfo.LinkTarget, usePathCombineInner, cancellationToken); + foreach (string relativePathFile in relativePathFiles) + results.Add(Path.GetFullPath(Path.Combine(subdirectory, relativePathFile))); } return new(results); } + internal static ReadOnlyCollection RemoteRemove(string repositoryDirectory, string name, CancellationToken cancellationToken) + { + List results = []; + Task task = RunAsync($"remote rm {name}", repositoryDirectory, cancellationToken); + task.Wait(cancellationToken); + string[] lines = task.Result.Split("\r\n"); + foreach (string line in lines) + results.Add(line); + return new(results); + } + + internal static ReadOnlyCollection RemoteAdd(string repositoryDirectory, string name, string url, CancellationToken cancellationToken) + { + List results = []; + Task task = RunAsync($"remote add {name} {url}", repositoryDirectory, cancellationToken); + task.Wait(cancellationToken); + string[] lines = task.Result.Split("\r\n"); + foreach (string line in lines) + results.Add(line); + return new(results); + } + + internal static ReadOnlyCollection PushBranch(string repositoryDirectory, string remote, string name, CancellationToken cancellationToken) + { + List results = []; + Task task = RunAsync($"push {remote} {name}", repositoryDirectory, cancellationToken); + task.Wait(cancellationToken); + string[] lines = task.Result.Split("\r\n"); + foreach (string line in lines) + results.Add(line); + return new(results); + } + } \ No newline at end of file diff --git a/Helpers/HelperKanbanMetadata.cs b/Helpers/HelperKanbanMetadata.cs index c80675d..dc88549 100644 --- a/Helpers/HelperKanbanMetadata.cs +++ b/Helpers/HelperKanbanMetadata.cs @@ -160,7 +160,7 @@ internal static partial class HelperKanbanMetadata results.Add(lines[i]); } } - results.Add($"status: \"{record.GroupCount}-{record.Group}\""); + results.Add($"status: {record.GroupCount}-{record.Group}"); results.Add("```"); results.Add(string.Empty); } @@ -201,7 +201,7 @@ internal static partial class HelperKanbanMetadata (lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(record.FileInfo); if (lines.Count == 0) continue; - statusLine = $"status: \"{record.GroupCount}-{record.Group}\""; + statusLine = $"status: {record.GroupCount}-{record.Group}"; paramCase = lineNumber.H1 is null ? null : GetParamCase(lines[lineNumber.H1.Value]); match = lineNumber.H1 is null || paramCase is null ? null : Path.GetFileNameWithoutExtension(record.FileInfo.Name) == paramCase; if (lineNumber.FrontMatterYamlEnd is null) diff --git a/Helpers/HelperMarkdown.cs b/Helpers/HelperMarkdown.cs index 74b5e59..eb0bef1 100644 --- a/Helpers/HelperMarkdown.cs +++ b/Helpers/HelperMarkdown.cs @@ -1,6 +1,7 @@ using File_Folder_Helper.Models; using Microsoft.Extensions.Logging; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Globalization; using System.Text; using System.Text.Json; @@ -15,7 +16,7 @@ internal static partial class HelperMarkdown private record Input(string? Destination, string Source, - string? StartAt); + bool UseProcessStart); private record Record(string Directory, string File, @@ -29,6 +30,7 @@ internal static partial class HelperMarkdown string FileNameWithoutExtension, ReadOnlyDictionary FrontMatterYaml, string H1, + bool IsGitOthersModifiedAndDeletedExcludingStandard, bool IsKanbanIndex, bool IsKanbanMarkdown, DateTime LastWriteDateTime, @@ -53,246 +55,9 @@ internal static partial class HelperMarkdown { } - private static void SetRecursiveLines(AppSettings appSettings, ILogger logger, ReadOnlyDictionary> keyValuePairs, string linkTitle, MarkdownFile markdownFile, string[] lines, List indentations, List recursiveLines) - { - if (recursiveLines is null) - throw new Exception(); - string file; - string[] segmentsA; - string[] segmentsB; - string segmentsALast; - bool fencedCodeBlock = false; - string indentation = new(indentations.ToArray()); - MarkdownFileH1AndRelativePath markdownFileH1AndRelativePath; - for (int i = 0; i < lines.Length; i++) - { - if (indentations.Count > 15) - { - recursiveLines.Add("```Error```"); - break; - } - if (lines[i].Length < 1) - continue; - if (lines[i].Length > 4 && lines[i][..3] == "```") - fencedCodeBlock = !fencedCodeBlock; - if (fencedCodeBlock) - continue; - if (lines[i][0] == '#') - { - if (lines[i] == $"# {linkTitle}") - continue; - recursiveLines.Add($"{indentation}{lines[i]}"); - continue; - } - segmentsA = lines[i].Split("]("); - if (segmentsA.Length != 2) - continue; - segmentsALast = segmentsA[^1]; - if (appSettings.ExcludeSchemes.Any(l => segmentsALast.StartsWith(l))) - continue; - segmentsB = segmentsALast.Split(")"); - if (segmentsB.Length != 2) - continue; - file = Path.GetFullPath(Path.Combine(markdownFile.Directory, segmentsB[0])); - markdownFileH1AndRelativePath = GetRelativePath(keyValuePairs, markdownFile, file); - if (markdownFileH1AndRelativePath.MarkdownFile is null || markdownFileH1AndRelativePath.H1 is null || markdownFileH1AndRelativePath.RelativePath is null) - { - recursiveLines.Add($"???{indentation}{lines[i]}"); - logger.LogInformation("Didn't find {line} in <{file}>", lines[i], markdownFile.FileNameWithoutExtension); - continue; - } - if (markdownFileH1AndRelativePath.Lines is null) - continue; - indentations.Add('\t'); - recursiveLines.Add($"{indentation}{lines[i]}"); - SetRecursiveLines(appSettings, logger, keyValuePairs, segmentsA[0].Split('[')[^1], markdownFileH1AndRelativePath.MarkdownFile, markdownFileH1AndRelativePath.Lines, indentations, recursiveLines); - } - if (indentations.Count > 0) - indentations.RemoveAt(0); - } - - private static List GetFrontMatterLines(string[] parsedLines) - { - List results = []; - string afterTrim; - string[] segments; - StringBuilder stringBuilder = new(); - for (int i = 0; i < parsedLines.Length; i++) - { - afterTrim = parsedLines[i].Trim(); - if (string.IsNullOrEmpty(afterTrim) || afterTrim[0] is '{' or '}') - continue; - segments = afterTrim.Split(": "); - if (segments.Length != 2) - { - if (results[^1][^1] == '[') - { - _ = stringBuilder.Clear(); - _ = stringBuilder.Append(results[^1]); - results.RemoveAt(results.Count - 1); - for (int j = i; j < parsedLines.Length; j++) - { - i = j; - afterTrim = parsedLines[j].Trim(); - if (afterTrim == "],") - _ = stringBuilder.Append(afterTrim[..^1]); - else if (afterTrim[^1] == ',') - _ = stringBuilder.Append(afterTrim).Append(' '); - else - _ = stringBuilder.Append(afterTrim); - if (afterTrim is "]" or "],") - { - results.Add(stringBuilder.ToString()); - break; - } - } - continue; - } - results.Clear(); - break; - } - if (afterTrim[^1] != ',') - results.Add(afterTrim[1..].Replace("\": ", ": ")); - else - results.Add(afterTrim[1..^1].Replace("\": ", ": ")); - } - return results; - } - - /// - /// Determines files text file's encoding by analyzing its byte order mark (BOM). - /// Defaults to ASCII when detection of the text file's endianness fails. - /// - /// The text file to analyze. - /// The detected encoding. - private static Encoding? GetEncoding(string filename) - { - Encoding? result; - byte[] bom = new byte[4]; - using FileStream file = new(filename, FileMode.Open, FileAccess.Read); - _ = file.Read(bom, 0, 4); - if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) -#pragma warning disable SYSLIB0001 - result = Encoding.UTF7; -#pragma warning restore SYSLIB0001 - if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) - result = Encoding.UTF8; - if (bom[0] == 0xff && bom[1] == 0xfe && bom[2] == 0 && bom[3] == 0) - result = Encoding.UTF32; //UTF-32LE - if (bom[0] == 0xff && bom[1] == 0xfe) - result = Encoding.Unicode; //UTF-16LE - if (bom[0] == 0xfe && bom[1] == 0xff) - result = Encoding.BigEndianUnicode; //UTF-16BE - if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) - result = new UTF32Encoding(true, true); //UTF-32BE - else - result = null; - return result; - } - [GeneratedRegex("(~~)?(#)([a-zA-Z0-9]{6})(~~)?( )")] private static partial Regex HtmlColor(); - private static List GetMarkdownFileAndLines(string file, List markdownFiles) - { - List results = []; - List distinct = []; - string? directory = Path.GetDirectoryName(file); - foreach (MarkdownFileAndLines markdownFileAndLines in markdownFiles) - { - if (string.IsNullOrEmpty(directory) || markdownFileAndLines.MarkdownFile.Directory != directory) - continue; - if (distinct.Contains(markdownFileAndLines.MarkdownFile.File)) - continue; - distinct.Add(markdownFileAndLines.MarkdownFile.File); - results.Add(markdownFileAndLines); - } - return results; - } - - private static (string?, Dictionary?, List) Get(List jsonLines) - { - string? result; - List results; - string jsonLinesLast = jsonLines[^1]; - jsonLines.RemoveAt(jsonLines.Count - 1); - jsonLines.Add(jsonLinesLast[..^1]); - jsonLines.Insert(0, "{"); - jsonLines.Add("}"); - Dictionary? keyValuePairs; - result = string.Join(Environment.NewLine, jsonLines); - keyValuePairs = JsonSerializer.Deserialize(result, DictionaryStringAndJsonElementSourceGenerationContext.Default.DictionaryStringJsonElement); - if (keyValuePairs is null) - throw new NullReferenceException(nameof(keyValuePairs)); - result = JsonSerializer.Serialize(keyValuePairs, DictionaryStringAndJsonElementSourceGenerationContext.Default.DictionaryStringJsonElement); - string[] parsedLines = result.Split(Environment.NewLine).ToArray(); - results = GetFrontMatterLines(parsedLines); - if (results.Count == 0) - { - result = null; - keyValuePairs = null; - } - return (result, keyValuePairs, results); - } - - internal static (List, LineNumber) GetStatusAndFrontMatterYamlEndLineNumbers(FileInfo fileInfo) - { - string line; - int? h1LineNumber = null; - int? typeLineNumber = null; - int? statusLineNumber = null; - int? createdLineNumber = null; - int? updatedLineNumber = null; - int? frontMatterYamlEndLineNumber = null; - Encoding? encoding = GetEncoding(fileInfo.FullName) ?? Encoding.Default; - string[] lines = File.ReadAllLines(fileInfo.FullName, encoding); - for (int i = 0; i < lines.Length; i++) - { - line = lines[i]; - if (line.Length < 3) - continue; - if (i == 0 && line[..3] == "---") - continue; - if (h1LineNumber is null && line[..3] == "---") - { - frontMatterYamlEndLineNumber = i; - continue; - } - if (line.Length > 6 && line[..6] == "type: ") - { - typeLineNumber = i; - continue; - } - if (line.Length > 8 && line[..8] == "status: ") - { - statusLineNumber = i; - continue; - } - if (line.Length > 9 && line[..9] == "created: ") - { - createdLineNumber = i; - continue; - } - if (line.Length > 9 && line[..9] == "updated: ") - { - updatedLineNumber = i; - continue; - } - if (h1LineNumber is null && line.Length > 2 && line[0] == '#' && line[1] == ' ') - { - h1LineNumber = i; - continue; - } - } - LineNumber lineNumber = new(createdLineNumber, - h1LineNumber, - frontMatterYamlEndLineNumber, - statusLineNumber, - typeLineNumber, - updatedLineNumber); - return (lines.ToList(), lineNumber); - } - private static MarkdownExtra GetMarkdownExtra(MarkdownFileAndLines markdownFileAndLines) { MarkdownExtra result; @@ -377,6 +142,129 @@ internal static partial class HelperMarkdown return result; } + private static List GetMarkdownFileAndLines(string file, List markdownFiles) + { + List results = []; + List distinct = []; + string? directory = Path.GetDirectoryName(file); + foreach (MarkdownFileAndLines markdownFileAndLines in markdownFiles) + { + if (string.IsNullOrEmpty(directory) || markdownFileAndLines.MarkdownFile.Directory != directory) + continue; + if (distinct.Contains(markdownFileAndLines.MarkdownFile.File)) + continue; + distinct.Add(markdownFileAndLines.MarkdownFile.File); + results.Add(markdownFileAndLines); + } + return results; + } + + private static string[] GetFiles(AppSettings appSettings, string directory, SearchOption searchOption) + { + string[] results = Directory.GetFiles(directory, "*.md", searchOption). + Where(l => !appSettings.ExcludeDirectoryNames.Any(m => l.Contains(m))).ToArray(); + return results; + } + + /// + /// Determines files text file's encoding by analyzing its byte order mark (BOM). + /// Defaults to ASCII when detection of the text file's endianness fails. + /// + /// The text file to analyze. + /// The detected encoding. + private static Encoding? GetEncoding(string filename) + { + Encoding? result; + byte[] bom = new byte[4]; + using FileStream file = new(filename, FileMode.Open, FileAccess.Read); + _ = file.Read(bom, 0, 4); + if (bom[0] == 0x2b && bom[1] == 0x2f && bom[2] == 0x76) +#pragma warning disable SYSLIB0001 + result = Encoding.UTF7; +#pragma warning restore SYSLIB0001 + if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf) + result = Encoding.UTF8; + if (bom[0] == 0xff && bom[1] == 0xfe && bom[2] == 0 && bom[3] == 0) + result = Encoding.UTF32; //UTF-32LE + if (bom[0] == 0xff && bom[1] == 0xfe) + result = Encoding.Unicode; //UTF-16LE + if (bom[0] == 0xfe && bom[1] == 0xff) + result = Encoding.BigEndianUnicode; //UTF-16BE + if (bom[0] == 0 && bom[1] == 0 && bom[2] == 0xfe && bom[3] == 0xff) + result = new UTF32Encoding(true, true); //UTF-32BE + else + result = null; + return result; + } + + private static ReadOnlyCollection GetFromMatterYamlLines(List lines, LineNumber lineNumber) + { + List results = []; + if (lineNumber.FrontMatterYamlEnd is not null && lines.Count >= lineNumber.FrontMatterYamlEnd.Value) + { + for (int i = 1; i < lineNumber.FrontMatterYamlEnd.Value; i++) + results.Add(lines[i]); + } + return new(results); + } + + private static List GetKeys(ReadOnlyDictionary relativeToCollection) + { + List results = []; + MarkdownFile markdownFile; + foreach (KeyValuePair relativeTo in relativeToCollection) + { + markdownFile = relativeTo.Value.MarkdownFile; + if (markdownFile.IsKanbanMarkdown) + continue; + results.Add(relativeTo.Key); + } + return results; + } + + private static void SetCards(Input input, ReadOnlyDictionary relativeToCollection, List notLinkedKey, MarkdownFile markdownFile, string[] lines, List cards, List allKeys, int i) + { + Card card; + string key; + string[] segmentsA; + MarkdownExtra markdownExtra; + MarkdownFileAndLines? markdownFileAndLines; + for (int j = i + 1; j < lines.Length; j++) + { + if (lines[j].Length < 5) + continue; + if (lines[j].Length >= 4 && lines[j][0] == '#' && lines[j][1] == '#' && lines[j][2] == ' ') + break; + segmentsA = lines[j].Split("]("); + if (segmentsA.Length != 2 || segmentsA[1][^1] != ')') + continue; + key = Path.GetRelativePath(input.Source, Path.Combine(markdownFile.Directory, segmentsA[1][..^1])); + if (!relativeToCollection.TryGetValue(key, out markdownFileAndLines)) + continue; + markdownExtra = GetMarkdownExtra(markdownFileAndLines); + card = new(markdownExtra.Assignees, + markdownFileAndLines.MarkdownFile.CreationDateTime, + markdownFileAndLines.MarkdownFile.Directory, + markdownExtra.Effort, + markdownFileAndLines.MarkdownFile.Extension, + markdownFileAndLines.MarkdownFile.File, + markdownFileAndLines.MarkdownFile.FileName, + markdownFileAndLines.MarkdownFile.FileNameWithoutExtension, + markdownFileAndLines.MarkdownFile.H1, + markdownExtra.H2HexColorCollection, + markdownExtra.H2NoCheckboxesCollection, + markdownExtra.H2WithCheckboxesCollection, + markdownFileAndLines.MarkdownFile.LastWriteDateTime, + markdownFileAndLines.MarkdownFile.LineNumber, + markdownExtra.RequestedDateTime, + markdownFileAndLines.MarkdownFile.Type); + if (allKeys.Remove(key)) + cards.Add(card); + else + notLinkedKey.Add(card); + } + } + private static List Distinct(IEnumerable? markdownFileAndLinesCollection) { List results = []; @@ -405,6 +293,125 @@ internal static partial class HelperMarkdown return results; } + private static ReadOnlyCollection GetFiles(AppSettings appSettings, Input input) + { + List results = []; + List files = []; + string[] directories = Directory.GetDirectories(input.Source, "*", SearchOption.AllDirectories); + foreach (string directory in directories) + { + files.Clear(); + files.AddRange(GetFiles(appSettings, directory, SearchOption.TopDirectoryOnly)); + foreach (string file in files) + results.Add(file); + } + return new(results); + } + + internal static (List, LineNumber) GetStatusAndFrontMatterYamlEndLineNumbers(FileInfo fileInfo) + { + string line; + int? h1LineNumber = null; + int? typeLineNumber = null; + int? statusLineNumber = null; + int? createdLineNumber = null; + int? updatedLineNumber = null; + int? frontMatterYamlEndLineNumber = null; + Encoding? encoding = GetEncoding(fileInfo.FullName) ?? Encoding.Default; + string[] lines = File.ReadAllLines(fileInfo.FullName, encoding); + for (int i = 0; i < lines.Length; i++) + { + line = lines[i]; + if (line.Length < 3) + continue; + if (i == 0 && line[..3] == "---") + continue; + if (h1LineNumber is null && line[..3] == "---") + { + frontMatterYamlEndLineNumber = i; + continue; + } + if (line.Length > 6 && line[..6] == "type: ") + { + typeLineNumber = i; + continue; + } + if (line.Length > 8 && line[..8] == "status: ") + { + statusLineNumber = i; + continue; + } + if (line.Length > 9 && line[..9] == "created: ") + { + createdLineNumber = i; + continue; + } + if (line.Length > 9 && line[..9] == "updated: ") + { + updatedLineNumber = i; + continue; + } + if (h1LineNumber is null && line.Length > 2 && line[0] == '#' && line[1] == ' ') + { + h1LineNumber = i; + continue; + } + } + LineNumber lineNumber = new(createdLineNumber, + h1LineNumber, + frontMatterYamlEndLineNumber, + statusLineNumber, + typeLineNumber, + updatedLineNumber); + return (lines.ToList(), lineNumber); + } + + private static Dictionary GetFromMatterYaml(ReadOnlyCollection frontMatterYamlLines) + { + Dictionary results = []; + string[] segments; + foreach (string line in frontMatterYamlLines.OrderBy(l => l)) + { + segments = line.Split(": "); + if (segments.Length != 2) + { + results.Clear(); + break; + } + if (segments[1] is "''" or "\"\"") + results.Add(segments[0], string.Empty); + else if (segments[1] == "[]") + results.Add(segments[0], Array.Empty()); + else + results.Add(segments[0], segments[1].Trim()); + } + return results; + } + + private static ReadOnlyDictionary GetFromMatterYaml(List lines, LineNumber lineNumber) + { + Dictionary results = []; +#pragma warning disable IL3050 + IDeserializer deserializer = new DeserializerBuilder().Build(); +#pragma warning restore IL3050 + ReadOnlyCollection frontMatterYamlLines = GetFromMatterYamlLines(lines, lineNumber); + if (!frontMatterYamlLines.Any(l => l.StartsWith(' '))) + results = GetFromMatterYaml(frontMatterYamlLines); + else + { + string frontMatterYaml = string.Join(Environment.NewLine, frontMatterYamlLines); + Dictionary? keyValuePairs = deserializer.Deserialize>(frontMatterYaml); + if (keyValuePairs is null) + results = GetFromMatterYaml(frontMatterYamlLines); + else + { + foreach (string key in keyValuePairs.Keys.OrderBy(l => l)) + results.Add(key, keyValuePairs[key]); + } + } + return new(results); + } + private static ReadOnlyDictionary> GetKeyValuePairs(ReadOnlyDictionary relativeToCollection) { Dictionary> results = []; @@ -467,11 +474,10 @@ internal static partial class HelperMarkdown return new(results); } - private static int ConvertFileToSlugName(ReadOnlyDictionary relativeToCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + private static int ConvertFileToSlugName(ReadOnlyDictionary relativeToCollection) { int result = 0; string h1; - bool gitCheck; string h1Check; string[] lines; string checkName; @@ -483,7 +489,6 @@ internal static partial class HelperMarkdown continue; lines = relativeTo.Value.Lines; markdownFile = relativeTo.Value.MarkdownFile; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File); if (markdownFile.LineNumber.H1 is not null) { h1 = lines[markdownFile.LineNumber.H1.Value]; @@ -492,7 +497,7 @@ internal static partial class HelperMarkdown h1Check = $"# {h1[2..]}"; if (h1Check.Length == h1.Length && h1Check != h1) { - if (!gitCheck) + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) continue; lines[markdownFile.LineNumber.H1.Value] = h1Check; File.WriteAllLines(markdownFile.File, lines); @@ -508,7 +513,7 @@ internal static partial class HelperMarkdown checkName = Path.Combine(markdownFile.Directory, checkFileName); if (checkName == markdownFile.File) continue; - if (!gitCheck) + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) continue; File.Move(markdownFile.File, checkName); result += 1; @@ -516,112 +521,6 @@ internal static partial class HelperMarkdown return result; } - private static string[] GetFiles(AppSettings appSettings, string directory) - { - string[] results = Directory.GetFiles(directory, "*.md", SearchOption.AllDirectories). - Where(l => !appSettings.ExcludeDirectoryNames.Any(m => l.Contains(m))).ToArray(); - return results; - } - - private static ReadOnlyCollection GetFromMatterYamlLines(List lines, LineNumber lineNumber) - { - List results = []; - if (lineNumber.FrontMatterYamlEnd is not null && lines.Count >= lineNumber.FrontMatterYamlEnd.Value) - { - for (int i = 1; i < lineNumber.FrontMatterYamlEnd.Value; i++) - results.Add(lines[i]); - } - return new(results); - } - - private static ReadOnlyDictionary GetFromMatterYaml(List lines, LineNumber lineNumber) - { - Dictionary results = []; - IDeserializer deserializer = new DeserializerBuilder().Build(); - ReadOnlyCollection frontMatterYamlLines = GetFromMatterYamlLines(lines, lineNumber); - string frontMatterYaml = string.Join(Environment.NewLine, frontMatterYamlLines); - Dictionary? keyValuePairs = deserializer.Deserialize>(frontMatterYaml); - if (keyValuePairs is not null) - { - foreach (string key in keyValuePairs.Keys.OrderBy(l => l)) - results.Add(key, keyValuePairs[key]); - } - return new(results); - } - - private static ReadOnlyDictionary GetRelativeToCollection(AppSettings appSettings, Input input, string[] files, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles, bool force) - { - Dictionary results = []; - string h1; - string key; - string type; - bool gitCheck; - FileInfo fileInfo; - bool isKanbanIndex; - List lines; - bool isKanbanMarkdown; - LineNumber lineNumber; - MarkdownFile markdownFile; - string fileNameWithoutExtension; - ReadOnlyDictionary frontMatterYaml; - foreach (string file in files) - { // cSpell:disable - fileInfo = new(file); - if (fileInfo.DirectoryName is null) - continue; - key = Path.GetRelativePath(input.Source, file); - (lines, lineNumber) = GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo); - fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName); - h1 = fileNameWithoutExtension.ToLower().Replace("%20", "-").Replace(' ', '-'); - frontMatterYaml = GetFromMatterYaml(lines, lineNumber); - if (lines.Count > 0) - (type, h1) = GetTypeAndH1(appSettings, h1, lines, lineNumber); - else - { - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(file); - if (!gitCheck) - continue; - type = appSettings.DefaultNoteType; - File.WriteAllLines(file, ["---", $"type: \"{type}\"", "---", string.Empty, $"# {h1}"]); - lines = File.ReadAllLines(file).ToList(); - } - isKanbanMarkdown = fileInfo.Name.EndsWith(".knb.md"); - isKanbanIndex = fileNameWithoutExtension == "index" && type.StartsWith("kanb", StringComparison.OrdinalIgnoreCase); - markdownFile = new(fileInfo.CreationTime, - fileInfo.DirectoryName, - fileInfo.Extension, - file, - fileInfo.Name, - fileNameWithoutExtension, - frontMatterYaml, - h1, - isKanbanIndex, - isKanbanMarkdown, - fileInfo.LastWriteTime, - lineNumber, - type); - if (force || input.StartAt is null || file.StartsWith(input.StartAt)) - results.Add(key, new(markdownFile, lines.ToArray())); - else - results.Add(key, new(markdownFile, [])); - } // cSpell:restore - return new(results); - } - - private static List GetKeys(ReadOnlyDictionary relativeToCollection) - { - List results = []; - MarkdownFile markdownFile; - foreach (KeyValuePair relativeTo in relativeToCollection) - { - markdownFile = relativeTo.Value.MarkdownFile; - if (markdownFile.IsKanbanMarkdown) - continue; - results.Add(relativeTo.Key); - } - return results; - } - private static MarkdownFileAndLines? GetKanbanIndexMarkdownFileAndLines(ReadOnlyDictionary keyValuePairs) { MarkdownFile markdownFile; @@ -642,49 +541,6 @@ internal static partial class HelperMarkdown return result; } - private static void SetCards(Input input, ReadOnlyDictionary relativeToCollection, List notLinkedKey, MarkdownFile markdownFile, string[] lines, List cards, List allKeys, int i) - { - Card card; - string key; - string[] segmentsA; - MarkdownExtra markdownExtra; - MarkdownFileAndLines? markdownFileAndLines; - for (int j = i + 1; j < lines.Length; j++) - { - if (lines[j].Length < 5) - continue; - if (lines[j].Length >= 4 && lines[j][0] == '#' && lines[j][1] == '#' && lines[j][2] == ' ') - break; - segmentsA = lines[j].Split("]("); - if (segmentsA.Length != 2 || segmentsA[1][^1] != ')') - continue; - key = Path.GetRelativePath(input.Source, Path.Combine(markdownFile.Directory, segmentsA[1][..^1])); - if (!relativeToCollection.TryGetValue(key, out markdownFileAndLines)) - continue; - markdownExtra = GetMarkdownExtra(markdownFileAndLines); - card = new(markdownExtra.Assignees, - markdownFileAndLines.MarkdownFile.CreationDateTime, - markdownFileAndLines.MarkdownFile.Directory, - markdownExtra.Effort, - markdownFileAndLines.MarkdownFile.Extension, - markdownFileAndLines.MarkdownFile.File, - markdownFileAndLines.MarkdownFile.FileName, - markdownFileAndLines.MarkdownFile.FileNameWithoutExtension, - markdownFileAndLines.MarkdownFile.H1, - markdownExtra.H2HexColorCollection, - markdownExtra.H2NoCheckboxesCollection, - markdownExtra.H2WithCheckboxesCollection, - markdownFileAndLines.MarkdownFile.LastWriteDateTime, - markdownFileAndLines.MarkdownFile.LineNumber, - markdownExtra.RequestedDateTime, - markdownFileAndLines.MarkdownFile.Type); - if (allKeys.Remove(key)) - cards.Add(card); - else - notLinkedKey.Add(card); - } - } - private static ReadOnlyDictionary> GetColumnsToCards(Input input, ReadOnlyDictionary relativeToCollection, MarkdownFileAndLines markdownFileAndLines) { Dictionary> results = []; @@ -772,24 +628,20 @@ internal static partial class HelperMarkdown private static Input GetInput(List args) { Input result; - string? startAt = null; string? destination = null; + bool useProcessStart = false; string source = Path.GetFullPath(args[0]); for (int i = 1; i < args.Count; i++) { if (args[i].Length == 2 && i + 1 < args.Count) { - if (args[i][1] == 's') - startAt = Path.GetFullPath(args[i + 1]); + if (args[i][1] == 'u') + useProcessStart = args[i + 1] == "true"; else if (args[i][1] == 'd') destination = Path.GetFullPath(args[i + 1]); i++; } } - if (startAt is not null && !Directory.Exists(startAt)) - throw new Exception($"Start at directory <{startAt}> doesn't exist!"); - if (startAt is not null && startAt.Length < source.Length) - throw new Exception($"Start at directory <{startAt}> must be a subdirectory!"); if (destination is not null) { string? root = Path.GetPathRoot(destination); @@ -798,16 +650,116 @@ internal static partial class HelperMarkdown if (!Directory.Exists(destination)) _ = Directory.CreateDirectory(destination); } - result = new(destination, source, startAt); + result = new(destination, source, useProcessStart); return result; } - private static int CircularReference(ILogger logger, ReadOnlyDictionary relativeToCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + private static ReadOnlyDictionary GetRelativeToCollection(AppSettings appSettings, Input input, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + { + Dictionary results = []; + string h1; + string key; + string type; + FileInfo fileInfo; + bool isKanbanIndex; + List lines; + bool isWithinSource; + bool isKanbanMarkdown; + LineNumber lineNumber; + MarkdownFile markdownFile; + string fileNameWithoutExtension; + ReadOnlyDictionary frontMatterYaml; + bool isGitOthersModifiedAndDeletedExcludingStandard; + ReadOnlyCollection files = GetFiles(appSettings, input); + foreach (string file in files) + { // cSpell:disable + fileInfo = new(file); + if (fileInfo.DirectoryName is null) + continue; + key = Path.GetRelativePath(input.Source, file); + isWithinSource = file.Contains(input.Source); + isGitOthersModifiedAndDeletedExcludingStandard = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(file); + if (!isWithinSource && results.ContainsKey(key)) + continue; + (lines, lineNumber) = GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo); + fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName); + h1 = fileNameWithoutExtension.ToLower().Replace("%20", "-").Replace(' ', '-'); + frontMatterYaml = GetFromMatterYaml(lines, lineNumber); + if (lines.Count > 0) + (type, h1) = GetTypeAndH1(appSettings, h1, lines, lineNumber); + else + { + if (!isGitOthersModifiedAndDeletedExcludingStandard) + continue; + type = appSettings.DefaultNoteType; + File.WriteAllLines(file, ["---", $"type: {type}\"", "---", string.Empty, $"# {h1}"]); + lines = File.ReadAllLines(file).ToList(); + } + isKanbanMarkdown = fileInfo.Name.EndsWith(".knb.md"); + isKanbanIndex = fileNameWithoutExtension == "index" && type.StartsWith("kanb", StringComparison.OrdinalIgnoreCase); + markdownFile = new(fileInfo.CreationTime, + fileInfo.DirectoryName, + fileInfo.Extension, + file, + fileInfo.Name, + fileNameWithoutExtension, + frontMatterYaml, + h1, + isGitOthersModifiedAndDeletedExcludingStandard, + isKanbanIndex, + isKanbanMarkdown, + fileInfo.LastWriteTime, + lineNumber, + type); + results.Add(key, new(markdownFile, lines.ToArray())); + } // cSpell:restore + return new(results); + } + + private static int SortFrontMatter(AppSettings appSettings, ILogger logger, Input input, ReadOnlyDictionary relativeToCollection) + { + int result = 0; + List results = []; + string[] lines; + string frontMatterYaml; + MarkdownFile markdownFile; + string[] frontMatterYamlLines; +#pragma warning disable IL3050 + ISerializer serializer = new SerializerBuilder().WithIndentedSequences().Build(); +#pragma warning restore IL3050 + foreach (KeyValuePair relativeTo in relativeToCollection) + { + results.Clear(); + if (relativeTo.Value.Lines.Length < 2) + continue; + lines = relativeTo.Value.Lines; + markdownFile = relativeTo.Value.MarkdownFile; + if (markdownFile.IsKanbanMarkdown) + continue; + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) + continue; + if (markdownFile.LineNumber.FrontMatterYamlEnd is null) + continue; + frontMatterYaml = serializer.Serialize(markdownFile.FrontMatterYaml).Trim(); + frontMatterYamlLines = frontMatterYaml.Split(Environment.NewLine); + results.Add("---"); + results.AddRange(frontMatterYamlLines); + for (int i = markdownFile.LineNumber.FrontMatterYamlEnd.Value; i < lines.Length; i++) + results.Add(lines[i]); + if (results.Count == lines.Length && string.Join('\r', lines) == string.Join('\r', results)) + continue; + File.WriteAllLines(markdownFile.File, results); + File.SetLastWriteTime(markdownFile.File, markdownFile.LastWriteDateTime); + result += 1; + } + return result; + } + + private static int CircularReference(ILogger logger, ReadOnlyDictionary relativeToCollection) { int result = 0; string line; string check; - bool gitCheck; string[] lines; bool circularReference; MarkdownFile markdownFile; @@ -818,6 +770,8 @@ internal static partial class HelperMarkdown circularReference = false; lines = relativeTo.Value.Lines; markdownFile = relativeTo.Value.MarkdownFile; + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) + continue; for (int i = 0; i < lines.Length; i++) { check = $"[[{markdownFile.FileNameWithoutExtension}]]"; @@ -857,22 +811,18 @@ internal static partial class HelperMarkdown } if (!circularReference) continue; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File); - if (!gitCheck) - continue; File.WriteAllLines(markdownFile.File, lines); result += 1; } return result; } - private static int FindReplace(ReadOnlyDictionary relativeToCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + private static int FindReplace(ReadOnlyDictionary relativeToCollection) { int result = 0; bool found; string line; string check; - bool gitCheck; string[] lines; MarkdownFile markdownFile; foreach (KeyValuePair relativeTo in relativeToCollection) @@ -882,6 +832,8 @@ internal static partial class HelperMarkdown found = false; lines = relativeTo.Value.Lines; markdownFile = relativeTo.Value.MarkdownFile; + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) + continue; for (int i = 0; i < lines.Length; i++) { check = $"[[K-A/"; @@ -908,21 +860,17 @@ internal static partial class HelperMarkdown } if (!found) continue; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File); - if (!gitCheck) - continue; File.WriteAllLines(markdownFile.File, lines); result += 1; } return result; } - private static int ConvertToRelativePath(ILogger logger, ReadOnlyDictionary relativeToCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + private static int ConvertToRelativePath(ILogger logger, Input input, ReadOnlyDictionary relativeToCollection) { int result = 0; bool write; string line; - bool gitCheck; string[] lines; string[] segmentsA; string[] segmentsB; @@ -937,6 +885,8 @@ internal static partial class HelperMarkdown write = false; lines = relativeTo.Value.Lines; markdownFile = relativeTo.Value.MarkdownFile; + if (!input.UseProcessStart && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) + continue; for (int i = 0; i < lines.Length; i++) { segmentsA = lines[i].Split("]]"); @@ -949,7 +899,9 @@ internal static partial class HelperMarkdown markdownFileH1AndRelativePath = GetRelativePath(keyValuePairs, markdownFile, segmentsC[0]); if (markdownFileH1AndRelativePath.MarkdownFile is null || markdownFileH1AndRelativePath.H1 is null || markdownFileH1AndRelativePath.RelativePath is null) { - logger.LogInformation("Didn't find {line} in <{file}>", lines[i], markdownFile.FileNameWithoutExtension); + logger.LogInformation("Didn't find '{line}' in <{file}>", lines[i], markdownFile.FileName); + if (input.UseProcessStart && File.Exists(markdownFile.File)) + _ = Process.Start(new ProcessStartInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "VSCodium", "VSCodium.exe"), markdownFile.File) { WorkingDirectory = input.Source }); continue; } line = $"{segmentsB[0]}[{markdownFileH1AndRelativePath.H1}]({markdownFileH1AndRelativePath.RelativePath.Replace('\\', '/')}){segmentsA[^1]}"; @@ -961,8 +913,7 @@ internal static partial class HelperMarkdown } if (!write) continue; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File); - if (!gitCheck) + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) continue; File.WriteAllLines(markdownFile.File, lines); result += 1; @@ -970,13 +921,12 @@ internal static partial class HelperMarkdown return result; } - private static int ConvertFileToSlugName(AppSettings appSettings, ILogger logger, ReadOnlyDictionary relativeToCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + private static int ConvertFileToSlugName(AppSettings appSettings, ILogger logger, Input input, ReadOnlyDictionary relativeToCollection) { int result = 0; bool write; string file; string line; - bool gitCheck; string[] lines; string fileName; string checkName; @@ -998,6 +948,8 @@ internal static partial class HelperMarkdown markdownFile = relativeTo.Value.MarkdownFile; if (markdownFile.IsKanbanIndex) continue; + if (!input.UseProcessStart && !markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) + continue; if (!File.Exists(markdownFile.File)) continue; write = false; @@ -1024,7 +976,9 @@ internal static partial class HelperMarkdown markdownFileH1AndRelativePath = GetRelativePath(keyValuePairs, markdownFile, file); if (markdownFileH1AndRelativePath.MarkdownFile is null || markdownFileH1AndRelativePath.H1 is null || markdownFileH1AndRelativePath.RelativePath is null) { - logger.LogInformation("Didn't find {line} in <{file}>", lines[i], markdownFile.FileNameWithoutExtension); + logger.LogInformation("Didn't find '{line}' in <{file}>", lines[i], markdownFile.FileName); + if (input.UseProcessStart && File.Exists(markdownFile.File)) + _ = Process.Start(new ProcessStartInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "VSCodium", "VSCodium.exe"), markdownFile.File) { WorkingDirectory = input.Source }); continue; } line = $"{string.Join('[', segmentsC, 0, segmentsC.Length - 1)}[{markdownFileH1AndRelativePath.H1}]({markdownFileH1AndRelativePath.RelativePath.Replace('\\', '/')}){segmentsB[^1]}"; @@ -1059,66 +1013,19 @@ internal static partial class HelperMarkdown } if (!write) continue; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File); - if (!gitCheck) + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) continue; File.WriteAllLines(markdownFile.File, lines); result += 1; } if (result == 0) - result = ConvertFileToSlugName(relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); + result = ConvertFileToSlugName(relativeToCollection); return result; } - private static ReadOnlyDictionary GetRelativeToCollection(AppSettings appSettings, Input input, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles, bool force = false) - { - ReadOnlyDictionary results; - string[] files = GetFiles(appSettings, input.Source); - results = GetRelativeToCollection(appSettings, input, files, gitOthersModifiedAndDeletedExcludingStandardFiles, force); - return new(results); - } - - private static List GetRecursiveLines(AppSettings appSettings, Input input, ILogger logger, ReadOnlyDictionary relativeToCollection) - { - List results = []; - string[] lines; - List indentations; - MarkdownFile markdownFile; - List recursiveLines; - ReadOnlyDictionary> keyValuePairs = GetKeyValuePairs(relativeToCollection); - foreach (KeyValuePair relativeTo in relativeToCollection) - { - if (relativeTo.Value.Lines.Length == 0) - continue; - if (input.StartAt is null || !relativeTo.Value.MarkdownFile.File.StartsWith(input.StartAt) || Path.GetFileName(relativeTo.Value.MarkdownFile.Directory) != Path.GetFileName(input.StartAt)) - continue; - indentations = []; - recursiveLines = []; - lines = relativeTo.Value.Lines; - markdownFile = relativeTo.Value.MarkdownFile; - SetRecursiveLines(appSettings, logger, keyValuePairs, markdownFile.FileNameWithoutExtension, markdownFile, lines, indentations, recursiveLines); - results.Add(new(relativeTo.Value.MarkdownFile, recursiveLines.ToArray())); - } - return results; - } - - private static void Write(Input input, List markdownFileAndLinesCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) - { - bool gitCheck; - foreach (MarkdownFileAndLines markdownFileAndLines in markdownFileAndLinesCollection) - { - if (input.Destination is null) - continue; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFileAndLines.MarkdownFile.File); - if (!gitCheck) - continue; - File.WriteAllLines(Path.Combine(input.Destination, markdownFileAndLines.MarkdownFile.FileName), markdownFileAndLines.Lines); - } - } - private static void SaveColumnToCards(Input input, ReadOnlyDictionary relativeToCollection) { - if (string.IsNullOrEmpty(input.StartAt) || string.IsNullOrEmpty(input.Destination)) + if (string.IsNullOrEmpty(input.Destination)) throw new NotSupportedException(); MarkdownFileAndLines? markdownFileAndLines = GetKanbanIndexMarkdownFileAndLines(relativeToCollection); if (markdownFileAndLines is not null && File.Exists(markdownFileAndLines.MarkdownFile.File)) @@ -1145,11 +1052,10 @@ internal static partial class HelperMarkdown return (type, h1FromFile); } - private static int SetFrontMatterAndH1(AppSettings appSettings, ILogger logger, Input input, ReadOnlyDictionary relativeToCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + private static int SetFrontMatterAndH1(AppSettings appSettings, ILogger logger, Input input, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles, ReadOnlyDictionary relativeToCollection) { int result = 0; List results = []; - bool gitCheck; string h1Line; string[] lines; string typeLine; @@ -1171,12 +1077,11 @@ internal static partial class HelperMarkdown if (markdownFile.IsKanbanMarkdown) continue; results.AddRange(lines); - typeLine = $"type: \"{appSettings.DefaultNoteType}\""; + typeLine = $"type: {appSettings.DefaultNoteType}"; h1Line = $"# {markdownFile.FileNameWithoutExtension}"; creationDateTime = markdownFile.CreationDateTime > markdownFile.LastWriteDateTime ? markdownFile.LastWriteDateTime : markdownFile.CreationDateTime; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File); - createdLine = $"created: \"{creationDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}\""; - updatedLine = $"updated: \"{markdownFile.LastWriteDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}\""; + createdLine = $"created: {creationDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}"; + updatedLine = $"updated: {markdownFile.LastWriteDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}"; if (markdownFile.IsKanbanIndex) HelperKanbanMetadata.SetMetadata(markdownFile.Directory, new(lines), markdownFile.LineNumber, gitOthersModifiedAndDeletedExcludingStandardFiles); if (markdownFile.LineNumber.FrontMatterYamlEnd is null) @@ -1190,7 +1095,7 @@ internal static partial class HelperMarkdown results.Insert(0, string.Empty); } results.Insert(0, "---"); - if (gitCheck) + if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) { results.Insert(0, updatedLine); results.Insert(0, createdLine); @@ -1208,7 +1113,7 @@ internal static partial class HelperMarkdown } if (markdownFile.LineNumber.Type is null) results.Insert(markdownFile.LineNumber.FrontMatterYamlEnd.Value, typeLine); - if (gitCheck) + if (markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) { if (markdownFile.LineNumber.Updated is null) results.Insert(markdownFile.LineNumber.FrontMatterYamlEnd.Value, updatedLine); @@ -1244,7 +1149,7 @@ internal static partial class HelperMarkdown } if (results.Count == lines.Length && string.Join('\r', lines) == string.Join('\r', results)) continue; - if (!gitCheck) + if (!markdownFile.IsGitOthersModifiedAndDeletedExcludingStandard) continue; File.WriteAllLines(markdownFile.File, results); File.SetLastWriteTime(markdownFile.File, markdownFile.LastWriteDateTime); @@ -1259,43 +1164,34 @@ internal static partial class HelperMarkdown return new(result?.MarkdownFile, result?.Lines, result?.MarkdownFile.H1, result is null ? null : Path.GetRelativePath(markdownFile.Directory, Path.GetFullPath(result.MarkdownFile.File))); } - private static int SortFrontMatter(AppSettings appSettings, ILogger logger, Input input, ReadOnlyDictionary relativeToCollection, ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles) + private static List GetTaskArgumentsForDayHelper20240623(Input input) { - int result = 0; + if (string.IsNullOrEmpty(input.Destination)) + throw new NotSupportedException(); List results = []; - bool gitCheck; - string[] lines; - string frontMatterYaml; - MarkdownFile markdownFile; - string[] frontMatterYamlLines; - ISerializer serializer = new SerializerBuilder().WithIndentedSequences().Build(); - foreach (KeyValuePair relativeTo in relativeToCollection) + string? vscodeDirectory = Path.GetDirectoryName(input.Destination); + string? taskFile = vscodeDirectory is null ? null : Path.Combine(vscodeDirectory, "tasks.json"); + if (!string.IsNullOrEmpty(taskFile) && File.Exists(taskFile)) { - results.Clear(); - if (relativeTo.Value.Lines.Length < 2) - continue; - lines = relativeTo.Value.Lines; - markdownFile = relativeTo.Value.MarkdownFile; - if (markdownFile.IsKanbanMarkdown) - continue; - gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File); - if (!gitCheck) - continue; - if (markdownFile.LineNumber.FrontMatterYamlEnd is null) - continue; - frontMatterYaml = serializer.Serialize(markdownFile.FrontMatterYaml).Trim(); - frontMatterYamlLines = frontMatterYaml.Split(Environment.NewLine); - results.Add("---"); - results.AddRange(frontMatterYamlLines); - for (int i = markdownFile.LineNumber.FrontMatterYamlEnd.Value; i < lines.Length; i++) - results.Add(lines[i]); - if (results.Count == lines.Length && string.Join('\r', lines) == string.Join('\r', results)) - continue; - File.WriteAllLines(markdownFile.File, results); - File.SetLastWriteTime(markdownFile.File, markdownFile.LastWriteDateTime); - result += 1; + string json = File.ReadAllText(taskFile); + VSCodeTasks? vsCodeTasks = JsonSerializer.Deserialize(json, VSCodeTasksSourceGenerationContext.Default.VSCodeTasks); + if (vsCodeTasks is not null && vsCodeTasks.TaskCollection is not null) + { + foreach (VSCodeTask vsCodeTask in vsCodeTasks.TaskCollection) + { + if (vsCodeTask.Arguments is null || vsCodeTask.Arguments.Count < 4 || vsCodeTask.Arguments[3] != "Day-Helper-2024-06-23") + continue; + if (results.Count > 0) + { + results.Clear(); + break; + } + results.AddRange(vsCodeTask.Arguments.Skip(2)); + break; + } + } } - return result; + return results; } internal static void MarkdownWikiLinkVerification(AppSettings appSettings, ILogger logger, List args, CancellationToken cancellationToken) @@ -1305,50 +1201,49 @@ internal static partial class HelperMarkdown Input input = GetInput(args); ReadOnlyCollection gitOthersModifiedAndDeletedExcludingStandardFiles = HelperGit.GetOthersModifiedAndDeletedExcludingStandardFiles(input.Source, usePathCombine, cancellationToken); ReadOnlyDictionary relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles); - updated = SetFrontMatterAndH1(appSettings, logger, input, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); + updated = SetFrontMatterAndH1(appSettings, logger, input, gitOthersModifiedAndDeletedExcludingStandardFiles, relativeToCollection); if (updated != 0) { relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles); logger.LogInformation("{updated} Markdown file(s) were updated", updated); } - updated = SortFrontMatter(appSettings, logger, input, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); + updated = SortFrontMatter(appSettings, logger, input, relativeToCollection); if (updated != 0) { relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles); logger.LogInformation("{updated} Markdown file(s) were updated", updated); } - updated = CircularReference(logger, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); + updated = CircularReference(logger, relativeToCollection); if (updated != 0) { relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles); logger.LogInformation("{updated} Markdown file(s) were updated", updated); } - updated = FindReplace(relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); + updated = FindReplace(relativeToCollection); if (updated != 0) { relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles); logger.LogInformation("{updated} Markdown file(s) were updated", updated); } - updated = ConvertToRelativePath(logger, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); + updated = ConvertToRelativePath(logger, input, relativeToCollection); if (updated != 0) { relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles); logger.LogInformation("{updated} Markdown file(s) were updated", updated); } - updated = ConvertFileToSlugName(appSettings, logger, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); + updated = ConvertFileToSlugName(appSettings, logger, input, relativeToCollection); if (updated != 0) { relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles); logger.LogInformation("{updated} Markdown file(s) were updated", updated); } - if (!string.IsNullOrEmpty(input.StartAt) && !string.IsNullOrEmpty(input.Destination)) + if (!string.IsNullOrEmpty(input.Destination)) { - relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles, force: true); - List markdownFileAndLinesCollection = GetRecursiveLines(appSettings, input, logger, relativeToCollection); - Write(input, markdownFileAndLinesCollection, gitOthersModifiedAndDeletedExcludingStandardFiles); - } - if (!string.IsNullOrEmpty(input.StartAt) && !string.IsNullOrEmpty(input.Destination)) SaveColumnToCards(input, relativeToCollection); + List taskArgumentsForDayHelper20240623 = GetTaskArgumentsForDayHelper20240623(input); + if (taskArgumentsForDayHelper20240623.Count > 0) + HelperDay.Select(appSettings, logger, taskArgumentsForDayHelper20240623, cancellationToken: CancellationToken.None); + } } } \ No newline at end of file diff --git a/Models/Host.cs b/Models/Host.cs new file mode 100644 index 0000000..b09ee29 --- /dev/null +++ b/Models/Host.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +namespace File_Folder_Helper.Models; + +public record Host([property: JsonPropertyName("a")] string? Id, + [property: JsonPropertyName("b")] string? Colon, + [property: JsonPropertyName("c")] string? Hyphen, + [property: JsonPropertyName("d")] string? Line, + [property: JsonPropertyName("e")] string? Count, + [property: JsonPropertyName("f")] string? Segments, + [property: JsonPropertyName("g")] string? Type, + [property: JsonPropertyName("h")] string? Device, + [property: JsonPropertyName("i")] string? Name, + [property: JsonPropertyName("j")] string? Location); + +[JsonSourceGenerationOptions(WriteIndented = true, AllowTrailingCommas = true)] +[JsonSerializable(typeof(Host[]))] +public partial class HostSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Models/NginxFileSystem.cs b/Models/NginxFileSystem.cs new file mode 100644 index 0000000..9682266 --- /dev/null +++ b/Models/NginxFileSystem.cs @@ -0,0 +1,30 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace File_Folder_Helper.Models; + +public record NginxFileSystem(string Name, + string Type, + string MTime, + float Size) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, NginxFileSystemSourceGenerationContext.Default.NginxFileSystem); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] +[JsonSerializable(typeof(NginxFileSystem))] +internal partial class NginxFileSystemSourceGenerationContext : JsonSerializerContext +{ +} + +[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] +[JsonSerializable(typeof(NginxFileSystem[]))] +internal partial class NginxFileSystemCollectionSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Models/VSCodeTasks.cs b/Models/VSCodeTasks.cs new file mode 100644 index 0000000..94bc40b --- /dev/null +++ b/Models/VSCodeTasks.cs @@ -0,0 +1,43 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace File_Folder_Helper.Models; + +public record VSCodeTask([property: JsonPropertyName("label")] string? Label, + [property: JsonPropertyName("command")] string? Command, + [property: JsonPropertyName("type")] string? Type, + [property: JsonPropertyName("args")] IReadOnlyList? Arguments, + [property: JsonPropertyName("script")] string? Script) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, VSCodeTaskSourceGenerationContext.Default.VSCodeTask); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true, PropertyNameCaseInsensitive = true)] +[JsonSerializable(typeof(VSCodeTask))] +internal partial class VSCodeTaskSourceGenerationContext : JsonSerializerContext +{ +} + +public record VSCodeTasks([property: JsonPropertyName("version")] string? Version, + [property: JsonPropertyName("tasks")] VSCodeTask[]? TaskCollection) +{ + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, VSCodeTasksSourceGenerationContext.Default.VSCodeTasks); + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true, PropertyNameCaseInsensitive = true)] +[JsonSerializable(typeof(VSCodeTasks))] +internal partial class VSCodeTasksSourceGenerationContext : JsonSerializerContext +{ +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index 67b2c9e..e5689be 100644 --- a/Program.cs +++ b/Program.cs @@ -12,7 +12,7 @@ internal class Program public static void Main(string[] args) { #pragma warning disable IL3050 - HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); + HostApplicationBuilder builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder(args); #pragma warning restore IL3050 _ = builder.Configuration.AddEnvironmentVariables(); _ = builder.Configuration.AddUserSecrets();