Minor changes

Empty file ISO
Add date back for just .kanbn
Removed HardcodedFileSearchAndSort
Sync with 01-23
JsonToTsv
System.Text.Json
White-List
Ready to move to Move Helper
Remove Whitelist
Force Start At
Check for .git directory before ls
Optional
Allow root for unc path
nuget bump
PreVerify
EnforceCodeStyleInBuild
dotnet_analyzer_diagnostic
HelperGit
searchDelegate
Host File
AlertIfNewDeviceIsConnected
AOT
SetFrontMatterAndH1
Match Error
Unknown with better logging
Undo 04-05
WriteAppendToHostConfFile
MonA
IsKanbanIndex
Dotnet Format Pre-commit
NPM
CreateWindowsShortcut
Working directory
Split description
Copy tests
Ready to test
Delete after a couple of days
GitConfigCleanUp
knb Files
This commit is contained in:
2024-01-08 13:57:27 -07:00
parent 84ad97ac6e
commit 4e3f06bb44
35 changed files with 1914 additions and 884 deletions

View File

@ -1,6 +1,7 @@
using File_Folder_Helper.Models;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
@ -11,6 +12,44 @@ namespace File_Folder_Helper.Helpers;
internal static partial class HelperMarkdown
{
private record Input(string? Destination,
string Source,
string? StartAt);
private record Record(string Directory,
string File,
string[] Lines);
private record MarkdownFile(DateTime CreationDateTime,
string Directory,
string Extension,
string File,
string FileName,
string FileNameWithoutExtension,
string H1,
bool IsKanbanIndex,
DateTime LastWriteDateTime,
LineNumber LineNumber,
string Type);
private record MarkdownFileAndLines(MarkdownFile MarkdownFile,
string[] Lines);
private record MarkdownExtra(ReadOnlyCollection<string>? Assignees,
string? Effort,
ReadOnlyCollection<H2HexColor>? H2HexColorCollection,
ReadOnlyCollection<H2NoCheckboxes>? H2NoCheckboxesCollection,
ReadOnlyCollection<H2WithCheckboxes>? H2WithCheckboxesCollection,
string? RequestedDateTime);
private record MarkdownFileH1AndRelativePath(MarkdownFile? MarkdownFile, string[]? Lines, string? H1, string? RelativePath);
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(Dictionary<string, JsonElement>))]
internal partial class DictionaryStringAndJsonElementSourceGenerationContext : JsonSerializerContext
{
}
private static void SetRecursiveLines(AppSettings appSettings, ILogger<Worker> logger, ReadOnlyDictionary<string, List<MarkdownFileAndLines>> keyValuePairs, string linkTitle, MarkdownFile markdownFile, string[] lines, List<char> indentations, List<string> recursiveLines)
{
if (recursiveLines is null)
@ -553,6 +592,7 @@ internal static partial class HelperMarkdown
string key;
string type;
FileInfo fileInfo;
bool isKanbanIndex;
List<string> lines;
LineNumber lineNumber;
MarkdownFile markdownFile;
@ -574,6 +614,7 @@ internal static partial class HelperMarkdown
File.WriteAllLines(file, ["---", $"type: \"{type}\"", "---", string.Empty, $"# {h1}"]);
lines = File.ReadAllLines(file).ToList();
}
isKanbanIndex = fileNameWithoutExtension == "index" && type == "Kanban";
markdownFile = new(fileInfo.CreationTime,
fileInfo.DirectoryName,
fileInfo.Extension,
@ -581,6 +622,7 @@ internal static partial class HelperMarkdown
fileInfo.Name,
fileNameWithoutExtension,
h1,
isKanbanIndex,
fileInfo.LastWriteTime,
lineNumber,
type);
@ -613,7 +655,7 @@ internal static partial class HelperMarkdown
continue;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.FileNameWithoutExtension != "index" || markdownFile.Type != "Kanban")
if (markdownFile.IsKanbanIndex)
continue;
if (!File.Exists(markdownFile.File))
continue;
@ -642,7 +684,7 @@ internal static partial class HelperMarkdown
continue;
key = Path.GetRelativePath(input.Source, Path.Combine(markdownFile.Directory, segmentsA[1][..^1]));
if (!allKeys.Remove(key))
throw new NotSupportedException();
continue;
if (!relativeToCollection.TryGetValue(key, out markdownFileAndLines))
continue;
markdownExtra = GetMarkdownExtra(markdownFileAndLines);
@ -765,6 +807,7 @@ internal static partial class HelperMarkdown
Input result;
string? startAt = null;
string? destination = null;
string source = Path.GetFullPath(args[0]);
for (int i = 1; i < args.Count; i++)
{
if (args[i].Length == 2 && i + 1 < args.Count)
@ -778,6 +821,8 @@ internal static partial class HelperMarkdown
}
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);
@ -786,7 +831,7 @@ internal static partial class HelperMarkdown
if (!Directory.Exists(destination))
_ = Directory.CreateDirectory(destination);
}
result = new(Path.GetFullPath(args[0]), startAt, destination);
result = new(destination, source, startAt);
return result;
}
@ -1019,7 +1064,7 @@ internal static partial class HelperMarkdown
continue;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (markdownFile.FileNameWithoutExtension == "index" && markdownFile.Directory.EndsWith(".kanbn"))
if (markdownFile.IsKanbanIndex)
continue;
if (!File.Exists(markdownFile.File))
continue;
@ -1064,7 +1109,7 @@ internal static partial class HelperMarkdown
continue;
File.Move(file, checkName);
}
else if (fileName != fileName.ToLower())
else if (!fileName.Equals(fileName, StringComparison.CurrentCultureIgnoreCase))
{
if (file != checkName)
{
@ -1138,134 +1183,21 @@ internal static partial class HelperMarkdown
if (string.IsNullOrEmpty(input.StartAt) || string.IsNullOrEmpty(input.Destination))
throw new NotSupportedException();
ReadOnlyDictionary<string, List<Card>> columnsToCards;
string jsonFile = Path.Combine(input.Destination, $"{nameof(columnsToCards)}.json");
if (File.Exists(jsonFile))
File.Delete(jsonFile);
columnsToCards = GetColumnsToCards(input, relativeToCollection);
if (columnsToCards.Count == 0)
File.WriteAllText(jsonFile, "{}");
else
int kanbanIndexFiles = (from l in relativeToCollection where l.Value.MarkdownFile.IsKanbanIndex select 1).Sum();
if (kanbanIndexFiles == 1)
{
string json = JsonSerializer.Serialize(columnsToCards, ColumnsAndCardsSourceGenerationContext.Default.ReadOnlyDictionaryStringListCard);
File.WriteAllText(jsonFile, json);
}
}
private static List<Record> GetWithLinksForHugo(AppSettings appSettings, Input input)
{
List<Record> results = [];
string file;
string line;
string[] lines;
string fileName;
string? directory;
string[] segmentsA;
string[] segmentsB;
string relativeFile;
string segmentsALast;
string segmentsBFirst;
MarkdownFile markdownFile;
int sourceDirectoryLength = input.Source.Length;
ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection = GetRelativeToCollection(appSettings, input);
foreach (KeyValuePair<string, MarkdownFileAndLines> relativeTo in relativeToCollection)
{
if (relativeTo.Value.Lines.Length == 0)
continue;
lines = relativeTo.Value.Lines;
markdownFile = relativeTo.Value.MarkdownFile;
if (input.Destination is null)
continue;
if (markdownFile.File.Length < sourceDirectoryLength)
continue;
if (!File.Exists(markdownFile.File))
continue;
fileName = $"{input.Destination}{markdownFile.File[sourceDirectoryLength..]}";
directory = Path.GetDirectoryName(fileName);
if (string.IsNullOrEmpty(directory))
continue;
for (int i = 0; i < lines.Length; i++)
string jsonFile = Path.Combine(input.Destination, $"{nameof(columnsToCards)}.json");
if (File.Exists(jsonFile))
File.Delete(jsonFile);
columnsToCards = GetColumnsToCards(input, relativeToCollection);
if (columnsToCards.Count == 0)
File.WriteAllText(jsonFile, "{}");
else
{
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;
segmentsBFirst = segmentsB[0];
if (!segmentsBFirst.EndsWith(".md"))
file = Path.GetFullPath(Path.Combine(markdownFile.Directory, segmentsBFirst));
else
file = Path.GetFullPath(Path.Combine(markdownFile.Directory, segmentsBFirst[..^3]));
relativeFile = Path.GetRelativePath(input.Source, file).Replace('\\', '/');
line = $"{segmentsA[0]}]({relativeFile}){segmentsB[^1]}";
if (lines[i] == line)
throw new NotSupportedException($"Line {i} shouldn't match with {line}");
lines[i] = line;
string json = JsonSerializer.Serialize(columnsToCards, ColumnsAndCardsSourceGenerationContext.Default.ReadOnlyDictionaryStringListCard);
File.WriteAllText(jsonFile, json);
}
results.Add(new(directory, fileName, lines));
}
return results;
}
private static List<string> GetDistinct(List<Record> collection)
{
List<string> results = [];
foreach (Record record in collection)
{
if (results.Contains(record.Directory))
continue;
results.Add(record.Directory);
}
return results;
}
private static void CreateMissingDirectories(List<string> directories)
{
foreach (string directory in directories)
{
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
}
}
private record Input(string Source,
string? StartAt,
string? Destination);
private record Record(string Directory,
string File,
string[] Lines);
private record MarkdownFile(DateTime CreationDateTime,
string Directory,
string Extension,
string File,
string FileName,
string FileNameWithoutExtension,
string H1,
DateTime LastWriteDateTime,
LineNumber LineNumber,
string Type);
private record MarkdownFileAndLines(MarkdownFile MarkdownFile,
string[] Lines);
private record MarkdownExtra(ReadOnlyCollection<string>? Assignees,
string? Effort,
ReadOnlyCollection<H2HexColor>? H2HexColorCollection,
ReadOnlyCollection<H2NoCheckboxes>? H2NoCheckboxesCollection,
ReadOnlyCollection<H2WithCheckboxes>? H2WithCheckboxesCollection,
string? RequestedDateTime);
private record MarkdownFileH1AndRelativePath(MarkdownFile? MarkdownFile, string[]? Lines, string? H1, string? RelativePath);
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(Dictionary<string, JsonElement>))]
internal partial class DictionaryStringAndJsonElementSourceGenerationContext : JsonSerializerContext
{
}
private static (string type, string h1) GetTypeAndH1(AppSettings appSettings, string h1, List<string> lines, LineNumber lineNumber)
@ -1275,14 +1207,22 @@ internal static partial class HelperMarkdown
return (type, h1FromFile);
}
private static int SetFrontMatterAndH1(AppSettings appSettings, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
private static int SetFrontMatterAndH1(AppSettings appSettings, Input input, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
{
int result = 0;
List<string> results = [];
bool gitCheck;
string h1Line;
string[] lines;
string typeLine;
TimeSpan timeSpan;
string createdLine;
string updatedLine;
string lineDateTime;
DateTime checkDateTime;
DateTime creationDateTime;
MarkdownFile markdownFile;
string lineCreationFormat = "yyyy-MM-ddTHH:mm:ss.fffZ";
foreach (KeyValuePair<string, MarkdownFileAndLines> relativeTo in relativeToCollection)
{
if (relativeTo.Value.Lines.Length == 0)
@ -1293,6 +1233,10 @@ internal static partial class HelperMarkdown
results.AddRange(lines);
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}\"";
if (markdownFile.LineNumber.FrontMatterYamlEnd is null)
{
if (markdownFile.LineNumber.H1 is null)
@ -1302,6 +1246,11 @@ internal static partial class HelperMarkdown
results.Insert(0, string.Empty);
}
results.Insert(0, "---");
if (gitCheck)
{
results.Insert(0, updatedLine);
results.Insert(0, createdLine);
}
results.Insert(0, typeLine);
results.Insert(0, "---");
}
@ -1315,9 +1264,42 @@ internal static partial class HelperMarkdown
}
if (markdownFile.LineNumber.Type is null)
results.Insert(markdownFile.LineNumber.FrontMatterYamlEnd.Value, typeLine);
if (markdownFile.LineNumber.H1 is not null && markdownFile.LineNumber.Type is not null)
continue;
if (gitCheck)
{
if (markdownFile.LineNumber.Updated is null)
results.Insert(markdownFile.LineNumber.FrontMatterYamlEnd.Value, updatedLine);
else
{
lineDateTime = results[markdownFile.LineNumber.Updated.Value].Split(": ")[1].Trim('"');
if (!DateTime.TryParseExact(lineDateTime, lineCreationFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime))
results[markdownFile.LineNumber.Updated.Value] = updatedLine;
else
{
timeSpan = new(checkDateTime.Ticks - markdownFile.LastWriteDateTime.Ticks);
if (timeSpan.TotalDays is > 1 or < -1)
results[markdownFile.LineNumber.Updated.Value] = updatedLine;
}
}
if (markdownFile.LineNumber.Created is null)
results.Insert(markdownFile.LineNumber.FrontMatterYamlEnd.Value, createdLine);
else
{
lineDateTime = results[markdownFile.LineNumber.Created.Value].Split(": ")[1].Trim('"');
if (!DateTime.TryParseExact(lineDateTime, lineCreationFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out checkDateTime))
results[markdownFile.LineNumber.Created.Value] = createdLine;
else
{
timeSpan = new(checkDateTime.Ticks - creationDateTime.Ticks);
if (timeSpan.TotalDays > 1)
results[markdownFile.LineNumber.Created.Value] = createdLine;
if (timeSpan.TotalDays < -1)
File.SetCreationTime(markdownFile.File, checkDateTime);
}
}
}
}
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;
@ -1331,13 +1313,14 @@ 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)));
}
internal static void MarkdownWikiLinkVerification(AppSettings appSettings, ILogger<Worker> logger, List<string> args)
internal static void MarkdownWikiLinkVerification(AppSettings appSettings, ILogger<Worker> logger, List<string> args, CancellationToken cancellationToken)
{
int updated;
bool usePathCombine = false;
Input input = GetInput(args);
ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection;
relativeToCollection = GetRelativeToCollection(appSettings, input);
updated = SetFrontMatterAndH1(appSettings, relativeToCollection);
ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection = GetRelativeToCollection(appSettings, input);
ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles = HelperGit.GetOthersModifiedAndDeletedExcludingStandardFiles(input.Source, usePathCombine, cancellationToken);
updated = SetFrontMatterAndH1(appSettings, input, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
if (updated != 0)
{
relativeToCollection = GetRelativeToCollection(appSettings, input);
@ -1383,18 +1366,4 @@ internal static partial class HelperMarkdown
SaveColumnToCards(input, relativeToCollection);
}
internal static void MarkdownConvertLinksForHugo(AppSettings appSettings, ILogger<Worker> logger, List<string> args)
{
Input input = GetInput(args);
if (string.IsNullOrEmpty(input.Destination))
throw new NotSupportedException("This method requires frontMatterYamlLines -d path!");
List<Record> collection = GetWithLinksForHugo(appSettings, input);
if (collection.Count == 0)
logger.LogInformation("No files?");
List<string> distinct = GetDistinct(collection);
CreateMissingDirectories(distinct);
foreach (Record record in collection)
File.WriteAllLines(record.File, record.Lines);
}
}