Update Subtasks In Markdown Files
Better ISO support Only reviewing Files when comparing Extracted sections from UpdateSubTasksInMarkdownFiles
This commit is contained in:
@ -1,31 +1,96 @@
|
||||
using File_Folder_Helper.Helpers;
|
||||
using File_Folder_Helper.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace File_Folder_Helper.ADO2024.PI2;
|
||||
|
||||
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);
|
||||
[GeneratedRegex("([A-Z]+(.))")]
|
||||
private static partial Regex UpperCase();
|
||||
|
||||
private static List<Record> GetRecords(string sourceDirectory, string searchPattern, string codeInsiders, string subTasks, string directoryFilter)
|
||||
[GeneratedRegex("[\\s!?.,@:;|\\\\/\"'`£$%\\^&*{}[\\]()<>~#+\\-=_¬]+")]
|
||||
private static partial Regex InvalidCharacter();
|
||||
|
||||
private record H1AndParamCase(string H1, string ParamCase);
|
||||
private record SubTaskLine(string Text, bool Done, long? Ticks, int? Line);
|
||||
private record Record(int? CodeInsidersLine, FileInfo FileInfo, LineNumber LineNumber, int? StopLine, int? SubTasksLine);
|
||||
|
||||
private record Input(long? AfterEpochTotalMilliseconds,
|
||||
string CodeInsiders,
|
||||
string? DestinationDirectory,
|
||||
string DirectoryFilter,
|
||||
string Done,
|
||||
string IndexFile,
|
||||
string SearchPattern,
|
||||
string SubTasks,
|
||||
string SourceDirectory,
|
||||
ReadOnlyCollection<string> Tasks);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Input))]
|
||||
private partial class InputSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static Record GetRecord(Input input, FileInfo fileInfo)
|
||||
{
|
||||
Record result;
|
||||
int? stopLine = null;
|
||||
int? subTasksLine = null;
|
||||
int? codeInsidersLine = null;
|
||||
LineNumber lineNumber = HelperMarkdown.GetLineNumbers(fileInfo);
|
||||
for (int i = 0; i < lineNumber.Lines.Count; i++)
|
||||
{
|
||||
if (lineNumber.Lines[i].StartsWith(input.CodeInsiders) && lineNumber.Lines[i][^1] == '"')
|
||||
{
|
||||
if (lineNumber.Lines.Count > i + 1 && lineNumber.Lines[i + 1] == "```")
|
||||
codeInsidersLine = i;
|
||||
}
|
||||
if (lineNumber.Lines[i] != input.SubTasks)
|
||||
continue;
|
||||
subTasksLine = i;
|
||||
if (codeInsidersLine is null)
|
||||
break;
|
||||
if (lineNumber.Lines.Count > i)
|
||||
{
|
||||
for (int j = i + 1; j < lineNumber.Lines.Count; j++)
|
||||
{
|
||||
if (lineNumber.Lines[j].Length > 0 && lineNumber.Lines[j][0] == '#')
|
||||
{
|
||||
stopLine = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stopLine ??= lineNumber.Lines.Count;
|
||||
break;
|
||||
}
|
||||
result = new(codeInsidersLine, fileInfo, lineNumber, stopLine, subTasksLine);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Record> GetRecords(Input input)
|
||||
{
|
||||
List<Record> results = [];
|
||||
int? stopLine;
|
||||
string[] lines;
|
||||
int? subTasksLine;
|
||||
int? codeInsidersLine;
|
||||
ReadOnlyCollection<string> directoryNames = HelperDirectory.GetDirectoryNames(sourceDirectory);
|
||||
if (!directoryNames.Any(l => l.StartsWith(directoryFilter, StringComparison.CurrentCultureIgnoreCase)))
|
||||
Record record;
|
||||
FileInfo fileInfo;
|
||||
string sourceDirectory = input.SourceDirectory;
|
||||
ReadOnlyCollection<string> directoryNames = HelperDirectory.GetDirectoryNames(input.SourceDirectory);
|
||||
if (!directoryNames.Any(l => l.StartsWith(input.DirectoryFilter, StringComparison.CurrentCultureIgnoreCase)))
|
||||
{
|
||||
string directoryName;
|
||||
string[] checkDirectories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
string[] checkDirectories = Directory.GetDirectories(input.SourceDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string checkDirectory in checkDirectories)
|
||||
{
|
||||
directoryName = Path.GetFileName(checkDirectory);
|
||||
if (directoryName.StartsWith(directoryFilter, StringComparison.CurrentCultureIgnoreCase))
|
||||
if (directoryName.StartsWith(input.DirectoryFilter, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
sourceDirectory = checkDirectory;
|
||||
break;
|
||||
@ -33,204 +98,506 @@ internal static partial class Helper20240623
|
||||
}
|
||||
}
|
||||
string[] subDirectories = Directory.GetDirectories(sourceDirectory, "*", SearchOption.TopDirectoryOnly);
|
||||
List<string> files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.TopDirectoryOnly).ToList();
|
||||
List<string> files = Directory.GetFiles(sourceDirectory, input.SearchPattern, SearchOption.TopDirectoryOnly).ToList();
|
||||
foreach (string subDirectory in subDirectories)
|
||||
files.AddRange(Directory.GetFiles(subDirectory, searchPattern, SearchOption.TopDirectoryOnly));
|
||||
files.AddRange(Directory.GetFiles(subDirectory, input.SearchPattern, SearchOption.TopDirectoryOnly));
|
||||
foreach (string file in files)
|
||||
{
|
||||
stopLine = null;
|
||||
subTasksLine = null;
|
||||
codeInsidersLine = null;
|
||||
lines = File.ReadAllLines(file);
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (lines[i].StartsWith(codeInsiders) && lines[i][^1] == '"')
|
||||
{
|
||||
if (lines.Length > i + 1 && lines[i + 1] == "```")
|
||||
codeInsidersLine = i;
|
||||
}
|
||||
if (lines[i] != subTasks)
|
||||
continue;
|
||||
subTasksLine = i;
|
||||
if (codeInsidersLine is null)
|
||||
break;
|
||||
if (lines.Length > i)
|
||||
{
|
||||
for (int j = i + 1; j < lines.Length; j++)
|
||||
{
|
||||
if (lines[j].Length > 0 && lines[j][0] == '#')
|
||||
{
|
||||
stopLine = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stopLine ??= lines.Length;
|
||||
break;
|
||||
}
|
||||
results.Add(new(codeInsidersLine, file, lines, stopLine, subTasksLine));
|
||||
fileInfo = new(file);
|
||||
record = GetRecord(input, fileInfo);
|
||||
results.Add(record);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<SubTaskLine> GetSubTasks(string subTasks, string[] tasks, bool? foundDone, string fallbackLine, FileInfo fileInfo)
|
||||
private static string GetParamCase(string value)
|
||||
{
|
||||
string result;
|
||||
StringBuilder stringBuilder = new(value);
|
||||
Match[] matches = UpperCase().Matches(value).ToArray();
|
||||
for (int i = matches.Length - 1; i > -1; i--)
|
||||
_ = stringBuilder.Insert(matches[i].Index, '-');
|
||||
string[] segments = InvalidCharacter().Split(stringBuilder.ToString().ToLower());
|
||||
result = string.Join('-', segments).Trim('-');
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<SubTaskLine> GetSubTaskLines(Input input, bool? foundDone, string fallbackLine, Record record)
|
||||
{
|
||||
List<SubTaskLine> results = [];
|
||||
char done;
|
||||
string line;
|
||||
string text;
|
||||
bool doneValue;
|
||||
string? h1 = null;
|
||||
SubTaskLine subTaskLine;
|
||||
bool foundSubTasks = false;
|
||||
int tasksZeroLength = tasks[0].Length;
|
||||
string[] lines = File.ReadAllLines(fileInfo.FullName);
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
int tasksZeroLength = input.Tasks[0].Length;
|
||||
long ticks = record.FileInfo.LastWriteTime.Ticks;
|
||||
for (int i = 0; i < record.LineNumber.Lines.Count; i++)
|
||||
{
|
||||
line = lines[i];
|
||||
if (line.StartsWith("# "))
|
||||
h1 = line[2..];
|
||||
if (!foundSubTasks && line == subTasks)
|
||||
line = record.LineNumber.Lines[i];
|
||||
if (!foundSubTasks && line == input.SubTasks)
|
||||
foundSubTasks = true;
|
||||
if (!foundSubTasks)
|
||||
continue;
|
||||
if (line.Length <= tasksZeroLength || !line.StartsWith(tasks[0]) || line[tasksZeroLength] is not ' ' and not 'x' || line[tasksZeroLength + 1] != ']')
|
||||
if (line.Length <= tasksZeroLength || !line.StartsWith(input.Tasks[0]) || line[tasksZeroLength] is not ' ' and not 'x' || line[tasksZeroLength + 1] != ']')
|
||||
continue;
|
||||
doneValue = foundDone is not null && foundDone.Value;
|
||||
subTaskLine = new($" {line}", doneValue, fileInfo.LastWriteTime.Ticks, i);
|
||||
subTaskLine = new($" {line}", doneValue, ticks, i);
|
||||
results.Add(subTaskLine);
|
||||
}
|
||||
doneValue = foundDone is not null && foundDone.Value;
|
||||
if (h1 is null)
|
||||
subTaskLine = new(fallbackLine, doneValue, fileInfo.LastWriteTime.Ticks, Line: null);
|
||||
if (record.LineNumber.H1 is null)
|
||||
subTaskLine = new(fallbackLine, doneValue, ticks, Line: null);
|
||||
else
|
||||
{
|
||||
fallbackLine = foundDone is null || !foundDone.Value ? $"- [ ] {fileInfo.LastWriteTime.Ticks} ~~~ {h1}" : $"- [x] {fileInfo.LastWriteTime.Ticks} ~~~ {h1}";
|
||||
subTaskLine = new(fallbackLine, doneValue, fileInfo.LastWriteTime.Ticks, Line: 0);
|
||||
done = foundDone is null || !foundDone.Value ? ' ' : 'x';
|
||||
string codeInsidersLine = record.CodeInsidersLine is null ? string.Empty : $" ~~{record.LineNumber.Lines[record.CodeInsidersLine.Value]}~~";
|
||||
text = $"- [{done}] {ticks} {record.LineNumber.Lines[record.LineNumber.H1.Value]}{codeInsidersLine}";
|
||||
subTaskLine = new(text, doneValue, ticks, Line: 0);
|
||||
}
|
||||
results.Add(subTaskLine);
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static void UpdateSubTasksInMarkdownFiles(ILogger<Worker> logger, List<string> args)
|
||||
private static string GetSeasonName(int dayOfYear)
|
||||
{
|
||||
int lineCheck;
|
||||
string result = dayOfYear switch
|
||||
{
|
||||
< 78 => "0.Winter",
|
||||
< 124 => "1.Spring",
|
||||
< 171 => "2.Spring",
|
||||
< 217 => "3.Summer",
|
||||
< 264 => "4.Summer",
|
||||
< 309 => "5.Fall",
|
||||
< 354 => "6.Fall",
|
||||
_ => "7.Winter"
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string[] GetIndexLines(string h1, ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection) =>
|
||||
[
|
||||
"---",
|
||||
"startedColumns:",
|
||||
" - 'In Progress'",
|
||||
"completedColumns:",
|
||||
" - Done",
|
||||
"---",
|
||||
string.Empty,
|
||||
$"# {h1}",
|
||||
string.Empty,
|
||||
"## Backlog",
|
||||
string.Empty,
|
||||
string.Join(Environment.NewLine, h1ParamCaseCollection.Select(l => $"- [{l.ParamCase}](tasks/{l.ParamCase}.md)")),
|
||||
string.Empty,
|
||||
"## Todo",
|
||||
string.Empty,
|
||||
"## In Progress",
|
||||
string.Empty,
|
||||
"## Done",
|
||||
string.Empty
|
||||
];
|
||||
|
||||
private static string[] GetCascadingStyleSheetsLines() =>
|
||||
[
|
||||
".kanbn-column-done .kanbn-column-task-list {",
|
||||
" border-color: #198038;",
|
||||
"}",
|
||||
string.Empty,
|
||||
".kanbn-task-data-created {",
|
||||
" display: none;",
|
||||
"}",
|
||||
string.Empty,
|
||||
".kanbn-task-data-workload {",
|
||||
" display: none;",
|
||||
"}"
|
||||
];
|
||||
|
||||
private static string GetSettingsLines() =>
|
||||
/*lang=json,strict*/ """
|
||||
{
|
||||
"[markdown]": {
|
||||
"editor.wordWrap": "off"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"kanbn"
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
private static string GetTasksLines(string directory) =>
|
||||
/*lang=json,strict*/ """
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "File-Folder-Helper AOT s X Day-Helper-2024-06-23",
|
||||
"type": "shell",
|
||||
"command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe",
|
||||
"args": [
|
||||
"s",
|
||||
"X",
|
||||
"{}",
|
||||
"Day-Helper-2024-06-23",
|
||||
"*.md",
|
||||
"##_Sub-tasks",
|
||||
"code-insiders",
|
||||
"index.md",
|
||||
"-_[,](",
|
||||
"##_Done",
|
||||
".kan",
|
||||
"D:/5-Other-Small/Kanban/Year-Season",
|
||||
"316940400000"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
""".Replace("{}", directory.Replace('\\', '/'));
|
||||
|
||||
private static void FileWriteAllText(string path, string contents)
|
||||
{
|
||||
// string checkJson = Regex.Replace(File.ReadAllText(path), @"\s+", " ", RegexOptions.Multiline);
|
||||
// if (Regex.Replace(singletonJson, @"\s+", " ", RegexOptions.Multiline) != checkJson)
|
||||
// File.WriteAllText(path, singletonJson);
|
||||
string old = !File.Exists(path) ? string.Empty : File.ReadAllText(path);
|
||||
if (old != contents)
|
||||
File.WriteAllText(path, contents);
|
||||
}
|
||||
|
||||
private static void FileWriteAllText(string path, string[] contents) =>
|
||||
FileWriteAllText(path, string.Join(Environment.NewLine, contents));
|
||||
|
||||
private static ReadOnlyCollection<H1AndParamCase> GetH1ParamCaseCollection(Input input, ReadOnlyCollection<string> lines)
|
||||
{
|
||||
List<H1AndParamCase> results = [];
|
||||
string h1;
|
||||
string line;
|
||||
string paramCase;
|
||||
bool foundSubTasks = false;
|
||||
H1AndParamCase h1AndParamCase;
|
||||
int tasksZeroLength = input.Tasks[0].Length;
|
||||
for (int i = 0; i < lines.Count; i++)
|
||||
{
|
||||
line = lines[i];
|
||||
if (!foundSubTasks && line == input.SubTasks)
|
||||
foundSubTasks = true;
|
||||
if (!foundSubTasks)
|
||||
continue;
|
||||
if (line.Length <= tasksZeroLength || !line.StartsWith(input.Tasks[0]) || line[tasksZeroLength] is not ' ' and not 'x' || line[tasksZeroLength + 1] != ']')
|
||||
continue;
|
||||
h1 = line[(tasksZeroLength + 3)..];
|
||||
if (string.IsNullOrEmpty(h1))
|
||||
continue;
|
||||
paramCase = GetParamCase(h1);
|
||||
h1AndParamCase = new(h1, paramCase);
|
||||
results.Add(h1AndParamCase);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static void CreateFiles(string directory, ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection)
|
||||
{
|
||||
foreach (H1AndParamCase h1ParamCase in h1ParamCaseCollection)
|
||||
FileWriteAllText(Path.Combine(directory, $"{h1ParamCase.ParamCase}.md"), $"# {h1ParamCase.H1}");
|
||||
}
|
||||
|
||||
private static string WriteAndGetIndexFile(string destinationDirectory, string h1, long verified, ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection)
|
||||
{
|
||||
string result;
|
||||
string[] indexLines = GetIndexLines(h1, h1ParamCaseCollection);
|
||||
DateTime utcEpochDateTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
DateTime dateTime = utcEpochDateTime.AddMilliseconds(verified).ToLocalTime();
|
||||
string seasonName = GetSeasonName(dateTime.DayOfYear);
|
||||
string verifiedDirectory = Path.Combine(destinationDirectory, $"{dateTime.Year}", $"{dateTime.Year}-{seasonName}", verified.ToString());
|
||||
string kanbanDirectory = Path.Combine(verifiedDirectory, ".kanbn");
|
||||
string tasksKanbanDirectory = Path.Combine(kanbanDirectory, "tasks");
|
||||
if (!Directory.Exists(tasksKanbanDirectory))
|
||||
_ = Directory.CreateDirectory(tasksKanbanDirectory);
|
||||
string verifiedVisualStudioCodeDirectory = Path.Combine(verifiedDirectory, ".vscode");
|
||||
if (!Directory.Exists(verifiedVisualStudioCodeDirectory))
|
||||
_ = Directory.CreateDirectory(verifiedVisualStudioCodeDirectory);
|
||||
result = Path.Combine(kanbanDirectory, "index.md");
|
||||
CreateFiles(tasksKanbanDirectory, h1ParamCaseCollection);
|
||||
FileWriteAllText(result, indexLines);
|
||||
FileWriteAllText(Path.Combine(kanbanDirectory, "board.css"), GetCascadingStyleSheetsLines());
|
||||
FileWriteAllText(Path.Combine(verifiedVisualStudioCodeDirectory, "settings.json"), GetSettingsLines());
|
||||
FileWriteAllText(Path.Combine(verifiedVisualStudioCodeDirectory, "tasks.json"), GetTasksLines(verifiedDirectory));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<SubTaskLine> GetSubTaskLines(Input input, FileInfo fileInfo, LineNumber lineNumber)
|
||||
{
|
||||
List<SubTaskLine> results = [];
|
||||
char done;
|
||||
FileInfo f;
|
||||
Record record;
|
||||
bool doneValue;
|
||||
bool? foundDone;
|
||||
FileInfo fileInfo;
|
||||
string[] newLines;
|
||||
string[] segments;
|
||||
List<string> lines;
|
||||
string fallbackLine;
|
||||
string[] indexLines;
|
||||
string checkDirectory;
|
||||
string done = args[7];
|
||||
List<string> indexFiles;
|
||||
SubTaskLine subTaskLine;
|
||||
string subTasks = args[3];
|
||||
List<string> oldLines = [];
|
||||
bool? foundDone = null;
|
||||
ReadOnlyCollection<SubTaskLine> subTaskLines;
|
||||
for (int i = 0; i < lineNumber.Lines.Count; i++)
|
||||
{
|
||||
if (lineNumber.Lines[i] == input.Done)
|
||||
foundDone = true;
|
||||
segments = lineNumber.Lines[i].Split(input.Tasks[1]);
|
||||
doneValue = foundDone is not null && foundDone.Value;
|
||||
if (segments.Length > 2 || !segments[0].StartsWith(input.Tasks[0]))
|
||||
continue;
|
||||
done = foundDone is null || !foundDone.Value ? ' ' : 'x';
|
||||
fallbackLine = $"- [{done}] {segments[0][input.Tasks[0].Length..]} ~~FallbackLine~~";
|
||||
if (string.IsNullOrEmpty(fileInfo.DirectoryName))
|
||||
continue;
|
||||
f = new(Path.GetFullPath(Path.Combine(fileInfo.DirectoryName, segments[1][..^1])));
|
||||
if (!f.Exists)
|
||||
{
|
||||
results.Add(new(fallbackLine, doneValue, Ticks: null, Line: null));
|
||||
continue;
|
||||
}
|
||||
record = GetRecord(input, f);
|
||||
if (lineNumber.H1 is not null && record.LineNumber.H1 is not null)
|
||||
{
|
||||
string a = lineNumber.Lines[lineNumber.H1.Value];
|
||||
string b = record.LineNumber.Lines[record.LineNumber.H1.Value];
|
||||
if (b != a)
|
||||
{
|
||||
if (b != a)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
subTaskLines = GetSubTaskLines(input, doneValue, fallbackLine, record);
|
||||
for (int j = subTaskLines.Count - 1; j >= 0; j--)
|
||||
results.Add(subTaskLines[j]);
|
||||
}
|
||||
return results.AsReadOnly();
|
||||
}
|
||||
|
||||
private static Input GetInput(List<string> args)
|
||||
{
|
||||
string indexFile = args[5];
|
||||
string searchPattern = args[2];
|
||||
string directoryFilter = args[8];
|
||||
string[] tasks = args[6].Split(',');
|
||||
string codeInsiders = $"{args[4]} \"";
|
||||
List<SubTaskLine> allSubTaskLines = [];
|
||||
ReadOnlyCollection<SubTaskLine> subTaskLines;
|
||||
string done = args[7].Replace('_', ' ');
|
||||
string subTasks = args[3].Replace('_', ' ');
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
List<Record> records = GetRecords(sourceDirectory, searchPattern, codeInsiders, subTasks, directoryFilter);
|
||||
foreach (Record record in from l in records orderby l.SubTasksLine is null, l.CodeInsidersLine is null select l)
|
||||
string? destinationDirectory = args.Count < 8 ? null : Path.GetFullPath(args[9]);
|
||||
long? afterEpochTotalMilliseconds = args.Count < 9 ? null : long.Parse(args[10]);
|
||||
ReadOnlyCollection<string> tasks = args[6].Split(',').Select(l => l.Replace('_', ' ')).ToArray().AsReadOnly();
|
||||
Input input = new(afterEpochTotalMilliseconds, codeInsiders, destinationDirectory, directoryFilter, done, indexFile, searchPattern, subTasks, sourceDirectory, tasks);
|
||||
if (input.Tasks[0] != "- [" || input.Tasks[1] != "](")
|
||||
throw new Exception(JsonSerializer.Serialize(input, InputSourceGenerationContext.Default.Input));
|
||||
return input;
|
||||
}
|
||||
|
||||
private static string? MaybeWriteAndGetIndexFile(Input input, Record record, string? checkDirectory)
|
||||
{
|
||||
string? result;
|
||||
if (string.IsNullOrEmpty(checkDirectory) || input.AfterEpochTotalMilliseconds is null || string.IsNullOrEmpty(input.DestinationDirectory) || !checkDirectory.Contains(input.DestinationDirectory))
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
if (record.SubTasksLine is null)
|
||||
continue;
|
||||
if (record.CodeInsidersLine is not null)
|
||||
logger.LogInformation("<{file}> has [{subTasks}]", Path.GetFileNameWithoutExtension(record.File), subTasks);
|
||||
if (record.LineNumber.H1 is null)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
logger.LogWarning("<{file}> has [{subTasks}] but doesn't have [{codeInsiders}]!", Path.GetFileNameWithoutExtension(record.File), subTasks, codeInsiders);
|
||||
continue;
|
||||
}
|
||||
if (record.StopLine is null)
|
||||
continue;
|
||||
checkDirectory = record.Lines[record.CodeInsidersLine.Value][codeInsiders.Length..^1];
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
{
|
||||
logger.LogError("<{checkDirectory}> doesn't exist", Path.GetFileName(checkDirectory));
|
||||
continue;
|
||||
}
|
||||
indexFiles = Directory.GetFiles(checkDirectory, indexFile, SearchOption.AllDirectories).ToList();
|
||||
if (indexFiles.Count != 1)
|
||||
{
|
||||
for (int i = indexFiles.Count - 1; i > -1; i--)
|
||||
string segment = Path.GetFileName(checkDirectory);
|
||||
DateTime utcEpochDateTime = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
long utcEpochTotalMilliseconds = (long)Math.Floor(DateTime.UtcNow.Subtract(utcEpochDateTime).TotalMilliseconds);
|
||||
if (!long.TryParse(segment, out long check) || check < input.AfterEpochTotalMilliseconds || check > utcEpochTotalMilliseconds)
|
||||
result = null;
|
||||
else
|
||||
{
|
||||
if (!indexFiles[i].Contains(directoryFilter, StringComparison.CurrentCultureIgnoreCase))
|
||||
indexFiles.RemoveAt(i);
|
||||
}
|
||||
if (indexFiles.Count != 1)
|
||||
{
|
||||
logger.LogError("<{checkDirectory}> doesn't have a [{indexFile}]", Path.GetFileName(checkDirectory), indexFile);
|
||||
continue;
|
||||
ReadOnlyCollection<H1AndParamCase> h1ParamCaseCollection = GetH1ParamCaseCollection(input, record.LineNumber.Lines);
|
||||
if (h1ParamCaseCollection.Count == 0)
|
||||
result = null;
|
||||
else
|
||||
result = WriteAndGetIndexFile(input.DestinationDirectory, record.LineNumber.Lines[record.LineNumber.H1.Value], check, h1ParamCaseCollection);
|
||||
}
|
||||
}
|
||||
foundDone = null;
|
||||
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++)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool FileWrite(Record record, List<string> newLines, double percent)
|
||||
{
|
||||
bool result = false;
|
||||
if (record.StopLine is not null && record.SubTasksLine is not null)
|
||||
{
|
||||
string contents;
|
||||
string progressLine;
|
||||
List<string> resultLines;
|
||||
resultLines = record.LineNumber.Lines.ToList();
|
||||
if (record.LineNumber.FrontMatterYamlEnd is not null)
|
||||
{
|
||||
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]))
|
||||
progressLine = $"progress: {percent}";
|
||||
if (record.LineNumber.Progress is not null)
|
||||
resultLines[record.LineNumber.Progress.Value] = progressLine;
|
||||
else
|
||||
{
|
||||
resultLines.Insert(record.LineNumber.FrontMatterYamlEnd.Value, progressLine);
|
||||
contents = string.Join(Environment.NewLine, resultLines);
|
||||
FileWriteAllText(record.FileInfo.FullName, contents);
|
||||
result = true;
|
||||
}
|
||||
if (!result && record.LineNumber.Completed is null && percent > 99.9)
|
||||
{
|
||||
resultLines.Insert(record.LineNumber.FrontMatterYamlEnd.Value, $"completed: {DateTime.Now:yyyy-MM-dd}");
|
||||
contents = string.Join(Environment.NewLine, resultLines);
|
||||
FileWriteAllText(record.FileInfo.FullName, contents);
|
||||
result = true;
|
||||
}
|
||||
if (!result && record.LineNumber.Completed is not null && percent < 99.9)
|
||||
{
|
||||
resultLines.RemoveAt(record.LineNumber.Completed.Value);
|
||||
contents = string.Join(Environment.NewLine, resultLines);
|
||||
FileWriteAllText(record.FileInfo.FullName, contents);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
for (int i = record.StopLine.Value - 1; i > record.SubTasksLine.Value + 1; i--)
|
||||
resultLines.RemoveAt(i);
|
||||
if (record.StopLine.Value == record.LineNumber.Lines.Count && resultLines[^1].Length == 0)
|
||||
resultLines.RemoveAt(resultLines.Count - 1);
|
||||
for (int i = 0; i < newLines.Count; i++)
|
||||
resultLines.Insert(record.SubTasksLine.Value + 1 + i, newLines[i]);
|
||||
resultLines.Insert(record.SubTasksLine.Value + 1, string.Empty);
|
||||
contents = string.Join(Environment.NewLine, resultLines);
|
||||
FileWriteAllText(record.FileInfo.FullName, contents);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static FileInfo GetIndexFileInfo(Input input, Record record, string codeInsidersLine)
|
||||
{
|
||||
FileInfo result;
|
||||
string? indexFile;
|
||||
List<string> results;
|
||||
string? checkDirectory = codeInsidersLine[input.CodeInsiders.Length..^1];
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(input.DestinationDirectory) && checkDirectory.Contains(input.DestinationDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
}
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
results = [];
|
||||
else
|
||||
{
|
||||
results = Directory.GetFiles(checkDirectory, input.IndexFile, SearchOption.AllDirectories).ToList();
|
||||
if (results.Count != 1)
|
||||
{
|
||||
for (int i = results.Count - 1; i > -1; i--)
|
||||
{
|
||||
if (!results[i].Contains(input.DirectoryFilter, StringComparison.CurrentCultureIgnoreCase))
|
||||
results.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
if (results.Count == 0)
|
||||
{
|
||||
indexFile = MaybeWriteAndGetIndexFile(input, record, checkDirectory);
|
||||
if (!string.IsNullOrEmpty(indexFile))
|
||||
results.Add(indexFile);
|
||||
}
|
||||
}
|
||||
result = results.Count == 0 ? new(Path.Combine(checkDirectory, input.IndexFile)) : new(results[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static void UpdateSubTasksInMarkdownFiles(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
bool reload;
|
||||
int allCount;
|
||||
int lineCheck;
|
||||
double percent;
|
||||
double doneCount;
|
||||
FileInfo fileInfo;
|
||||
List<Record> records;
|
||||
LineNumber lineNumber;
|
||||
List<string> newLines;
|
||||
bool reloadAny = false;
|
||||
string? checkDirectory;
|
||||
string codeInsidersLine;
|
||||
List<string> oldLines = [];
|
||||
Input input = GetInput(args);
|
||||
string fileNameWithoutExtension;
|
||||
ReadOnlyCollection<SubTaskLine> subTaskLines;
|
||||
for (int z = 0; z < 9; z++)
|
||||
{
|
||||
records = GetRecords(input);
|
||||
foreach (Record record in from l in records orderby l.SubTasksLine is null, l.CodeInsidersLine is null select l)
|
||||
{
|
||||
if (record.SubTasksLine is null)
|
||||
continue;
|
||||
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])));
|
||||
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(record.FileInfo.FullName);
|
||||
if (record.CodeInsidersLine is not null)
|
||||
logger.LogInformation("<{file}> has [{subTasks}]", fileNameWithoutExtension, input.SubTasks);
|
||||
else
|
||||
{
|
||||
logger.LogWarning("<{file}> has [{subTasks}] but doesn't have [{codeInsiders}]!", fileNameWithoutExtension, input.SubTasks, input.CodeInsiders);
|
||||
continue;
|
||||
}
|
||||
if (record.StopLine is null)
|
||||
continue;
|
||||
codeInsidersLine = record.LineNumber.Lines[record.CodeInsidersLine.Value];
|
||||
fileInfo = GetIndexFileInfo(input, record, codeInsidersLine);
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
allSubTaskLines.Add(new(fallbackLine, doneValue, Ticks: null, Line: null));
|
||||
checkDirectory = codeInsidersLine[input.CodeInsiders.Length..^1];
|
||||
logger.LogError("<{checkDirectory}> doesn't have a [{indexFile}]", Path.GetFileName(checkDirectory), input.IndexFile);
|
||||
continue;
|
||||
}
|
||||
subTaskLines = GetSubTasks(subTasks, tasks, doneValue, fallbackLine, fileInfo);
|
||||
if (subTaskLines.Count > 0)
|
||||
oldLines.Clear();
|
||||
checkDirectory = fileInfo.DirectoryName;
|
||||
lineNumber = HelperMarkdown.GetLineNumbers(fileInfo);
|
||||
subTaskLines = GetSubTaskLines(input, fileInfo, lineNumber);
|
||||
if (subTaskLines.Count == 0)
|
||||
continue;
|
||||
lineCheck = 0;
|
||||
for (int i = record.SubTasksLine.Value + 1; i < record.StopLine.Value - 1; i++)
|
||||
oldLines.Add(record.LineNumber.Lines[i]);
|
||||
if (subTaskLines.Any(l => l.Ticks is null))
|
||||
newLines = (from l in subTaskLines select l.Text).ToList();
|
||||
else
|
||||
newLines = (from l in subTaskLines orderby l.Done descending, l.Ticks, l.Line select l.Text).ToList();
|
||||
if (subTaskLines.Count == 0)
|
||||
percent = 0;
|
||||
else
|
||||
{
|
||||
subTaskLine = new($"", false, null, null);
|
||||
allSubTaskLines.Add(subTaskLine);
|
||||
for (int j = subTaskLines.Count - 1; j >= 0; j--)
|
||||
allSubTaskLines.Add(subTaskLines[j]);
|
||||
allCount = (from l in subTaskLines where l.Line is not null && l.Line.Value == 0 select 1).Count();
|
||||
doneCount = (from l in subTaskLines where l.Line is not null && l.Line.Value == 0 && l.Done select 1).Count();
|
||||
// done = allCount != doneCount ? ' ' : 'x';
|
||||
percent = allCount == 0 ? 0 : Math.Round(doneCount / allCount, 3);
|
||||
// newLines.Insert(0, $"- [{done}] Sub-tasks {doneCount} of {allCount} [{percent * 100}%]");
|
||||
}
|
||||
}
|
||||
if (allSubTaskLines.Count == 0)
|
||||
continue;
|
||||
lineCheck = 0;
|
||||
for (int i = record.SubTasksLine.Value + 1; i < record.StopLine.Value - 1; i++)
|
||||
oldLines.Add(record.Lines[i]);
|
||||
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.Length; i++)
|
||||
if (newLines.Count == oldLines.Count)
|
||||
{
|
||||
if (newLines[i] != record.Lines[record.SubTasksLine.Value + 1 + i])
|
||||
for (int i = 0; i < newLines.Count; i++)
|
||||
{
|
||||
if (newLines[i] != record.LineNumber.Lines[record.SubTasksLine.Value + 1 + i])
|
||||
continue;
|
||||
lineCheck++;
|
||||
}
|
||||
if (lineCheck == newLines.Count)
|
||||
continue;
|
||||
lineCheck++;
|
||||
}
|
||||
if (lineCheck == newLines.Length)
|
||||
if (string.IsNullOrEmpty(checkDirectory))
|
||||
continue;
|
||||
checkDirectory = Path.Combine(checkDirectory, DateTime.Now.Ticks.ToString());
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
Thread.Sleep(500);
|
||||
Directory.Delete(checkDirectory);
|
||||
reload = FileWrite(record, newLines, percent);
|
||||
if (!reloadAny && reload)
|
||||
reloadAny = true;
|
||||
}
|
||||
checkDirectory = Path.Combine(checkDirectory, DateTime.Now.Ticks.ToString());
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
Thread.Sleep(500);
|
||||
Directory.Delete(checkDirectory);
|
||||
lines = record.Lines.ToList();
|
||||
for (int i = record.StopLine.Value - 1; i > record.SubTasksLine.Value + 1; i--)
|
||||
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.Length; i++)
|
||||
lines.Insert(record.SubTasksLine.Value + 1 + i, newLines[i]);
|
||||
lines.Insert(record.SubTasksLine.Value + 1, string.Empty);
|
||||
File.WriteAllLines(record.File, lines);
|
||||
if (!reloadAny)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user