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:
@ -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);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user