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

@ -0,0 +1,42 @@
namespace File_Folder_Helper.Helpers;
internal static class HelperDirectory
{
internal static List<string> GetDirectoryNames(string directory)
{
List<string> results = [];
string? fileName;
string? checkDirectory = directory;
string? pathRoot = Path.GetPathRoot(directory);
string extension = Path.GetExtension(directory);
if (string.IsNullOrEmpty(pathRoot))
throw new NullReferenceException(nameof(pathRoot));
if (Directory.Exists(directory))
{
fileName = Path.GetFileName(directory);
if (!string.IsNullOrEmpty(fileName))
results.Add(fileName);
}
else if ((string.IsNullOrEmpty(extension) || extension.Length > 3) && !File.Exists(directory))
{
fileName = Path.GetFileName(directory);
if (!string.IsNullOrEmpty(fileName))
results.Add(fileName);
}
for (int i = 0; i < int.MaxValue; i++)
{
checkDirectory = Path.GetDirectoryName(checkDirectory);
if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot)
break;
fileName = Path.GetFileName(checkDirectory);
if (string.IsNullOrEmpty(fileName))
continue;
results.Add(fileName);
}
results.Add(pathRoot);
results.Reverse();
return results;
}
}

66
Helpers/HelperGit.cs Normal file
View File

@ -0,0 +1,66 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
namespace File_Folder_Helper.Helpers;
internal static class HelperGit
{
private record ProcessResult(string Errors,
int ExitCode,
string Output);
private static async Task<ProcessResult> RunProcessAsync(string application, string arguments, string workingDirectory, CancellationToken cancellationToken)
{
using Process process = new();
StringBuilder outputBuilder = new();
StringBuilder errorsBuilder = new();
process.StartInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
FileName = application,
Arguments = arguments,
WorkingDirectory = workingDirectory,
};
process.OutputDataReceived += (_, args) => outputBuilder.AppendLine(args.Data);
process.ErrorDataReceived += (_, args) => errorsBuilder.AppendLine(args.Data);
_ = process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
await process.WaitForExitAsync(cancellationToken);
return new(errorsBuilder.ToString().Trim(), process.ExitCode, outputBuilder.ToString().Trim());
}
private static async Task<string> RunAsync(string arguments, string workingDirectory, CancellationToken cancellationToken)
{
ProcessResult result = await RunProcessAsync("git", arguments, workingDirectory, cancellationToken);
if (result.ExitCode != 0)
throw new Exception($"{result.ExitCode} {result.Errors}");
return result.Output;
}
internal static ReadOnlyCollection<string> GetOthersModifiedAndDeletedExcludingStandardFiles(string repositoryDirectory, bool usePathCombine, CancellationToken cancellationToken)
{
List<string> results = [];
string checkDirectory = Path.Combine(repositoryDirectory, ".git");
if (Directory.Exists(checkDirectory))
{
Task<string> 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 new(results);
}
}

View File

@ -1,84 +0,0 @@
using Microsoft.Extensions.Logging;
using System.Globalization;
namespace File_Folder_Helper.Helpers;
internal static class HelperHardcodedFileSearchAndSort
{
internal static void HardcodedFileSearchAndSort(ILogger log, string sourceDirectory, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
bool check;
string lines;
string checkFile;
string? directory;
FileInfo fileInfo;
string weekOfYear;
string checkDirectory;
CultureInfo cultureInfo = new("en-US");
Calendar calendar = cultureInfo.Calendar;
string[] hardcodedValues =
[
"BIORAD2",
"BIORAD3",
"BIORAD4",
"BIORAD5",
"CDE2",
"CDE3",
"CDE4",
"CDE5",
"CDE6",
"HGCV1",
"HGCV2",
"HGCV3",
"TENCOR1",
"TENCOR2",
"TENCOR3",
"SP101",
"SPV01",
"SRP",
"WC6Inch",
"WC8Inch",
"Bio-Rad"
];
string[] files = Directory.GetFiles(sourceDirectory, "*", searchOption);
foreach (string file in files)
{
directory = Path.GetDirectoryName(file);
if (string.IsNullOrEmpty(directory))
continue;
check = false;
fileInfo = new(file);
weekOfYear = calendar.GetWeekOfYear(fileInfo.LastWriteTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00");
for (int i = 1; i < 3; i++)
{
if (check)
break;
lines = i switch
{
1 => fileInfo.Name,
2 => File.ReadAllText(file),
_ => throw new NotImplementedException()
};
foreach (string hardcodedValue in hardcodedValues)
{
if (!lines.Contains(hardcodedValue))
continue;
checkDirectory = Path.Combine(directory, $"{fileInfo.LastWriteTime:yyyy}_Week_{weekOfYear}", fileInfo.LastWriteTime.ToString("yyyy-MM-dd"), hardcodedValue);
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
checkFile = Path.Combine(checkDirectory, Path.GetFileName(file));
if (File.Exists(checkFile) || !File.Exists(file))
continue;
try
{ File.Move(file, checkFile); }
catch (Exception) { }
check = true;
break;
}
}
}
log.LogInformation("{sourceDirectory}", sourceDirectory);
}
}

View File

@ -1,5 +1,6 @@
using File_Folder_Helper.Models;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
@ -14,6 +15,11 @@ internal static partial class HelperKanbanMetadata
[GeneratedRegex("[\\s!?.,@:;|\\\\/\"'`£$%\\^&*{}[\\]()<>~#+\\-=_¬]+")]
private static partial Regex InvalidCharacter();
private record Record(FileInfo FileInfo,
string Group,
int GroupCount,
int ItemLineNumber);
private static string GetParamCase(string value)
{
string result;
@ -64,15 +70,15 @@ internal static partial class HelperKanbanMetadata
throw new Exception("я надеюсь, что это сработает");
}
private static List<(int, int, string, FileInfo)> GetCollectionFromIndex(string sourceDirectory, string[] lines)
private static List<Record> GetCollectionFromIndex(string sourceDirectory, ReadOnlyCollection<string> lines)
{
List<(int, int, string, FileInfo)> results = [];
List<Record> results = [];
string line;
FileInfo fileInfo;
string[] segments;
int groupCount = 0;
string? group = null;
for (int i = 0; i < lines.Length; i++)
for (int i = 0; i < lines.Count; i++)
{
line = lines[i];
if (line.Length < 4)
@ -91,12 +97,30 @@ internal static partial class HelperKanbanMetadata
fileInfo = new(Path.Combine(sourceDirectory, segments[1][..^1]));
if (!fileInfo.Exists)
continue;
results.Add((groupCount, i, group, fileInfo));
results.Add(new(fileInfo, group, groupCount, i));
}
return results;
}
internal static void SetMetadata(ILogger log, AppSettings appSettings, string sourceDirectory, bool addTicks)
private static void WriteKanbanBoardFile(string fullPath, List<Record> records, string h1)
{
string? last = null;
List<string> lines = [h1, string.Empty];
foreach (Record record in records)
{
if (last is null || record.Group != last)
{
lines.Add(string.Empty);
lines.Add($"## {record.Group}");
lines.Add(string.Empty);
}
lines.Add($"- [ ] {Path.GetFileNameWithoutExtension(record.FileInfo.Name)}");
last = record.Group;
}
File.WriteAllLines(Path.Combine(fullPath, "index.knb.md"), lines);
}
internal static void SetMetadata(ILogger log, AppSettings appSettings, string sourceDirectory)
{
bool? match;
string? paramCase;
@ -112,20 +136,22 @@ internal static partial class HelperKanbanMetadata
string indexFile = Path.Combine(fullPath, "index.md");
if (File.Exists(indexFile))
{
string[] indexFileLines = File.ReadAllLines(indexFile);
List<(int, int, string, FileInfo)> collectionFromIndex = GetCollectionFromIndex(sourceDirectory, indexFileLines);
foreach ((int groupCount, int itemLineNumber, string group, FileInfo fileInfo) in collectionFromIndex)
FileInfo fileInfo = new(indexFile);
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo);
ReadOnlyCollection<string> indexFileLines = new(lines);
List<Record> records = GetCollectionFromIndex(sourceDirectory, indexFileLines);
if (lineNumber.H1 is not null)
WriteKanbanBoardFile(fullPath, records, indexFileLines[lineNumber.H1.Value]);
foreach (Record record in records)
{
if (itemLineNumber == 0)
if (record.ItemLineNumber == 0)
throw new NotSupportedException();
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo);
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(record.FileInfo);
if (lines.Count == 0)
continue;
statusLine = $"status: \"{groupCount}-{group}\"";
statusLine = $"status: \"{record.GroupCount}-{record.Group}\"";
paramCase = lineNumber.H1 is null ? null : GetParamCase(lines[lineNumber.H1.Value]);
if (addTicks)
indexFileLines[itemLineNumber] = $"{fileInfo.LastWriteTime.Ticks}~~~{indexFileLines[itemLineNumber]}";
match = lineNumber.H1 is null || paramCase is null ? null : Path.GetFileNameWithoutExtension(fileInfo.Name) == paramCase;
match = lineNumber.H1 is null || paramCase is null ? null : Path.GetFileNameWithoutExtension(record.FileInfo.Name) == paramCase;
if (lineNumber.FrontMatterYamlEnd is null)
throw new NotSupportedException($"{nameof(SetMetadata)} must be executed first!");
if (lineNumber.H1 is not null && paramCase is not null && match is not null && !match.Value)
@ -138,10 +164,8 @@ internal static partial class HelperKanbanMetadata
continue;
lines[lineNumber.Status.Value] = statusLine;
}
File.WriteAllLines(fileInfo.FullName, lines);
File.WriteAllLines(record.FileInfo.FullName, lines);
}
if (addTicks)
File.WriteAllLines(indexFile, indexFileLines);
}
}

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);
}
}

30
Helpers/HelperNPM.cs Normal file
View File

@ -0,0 +1,30 @@
using System.Diagnostics;
namespace File_Folder_Helper.Helpers;
internal static class HelperNPM
{
internal static string RunCommand(string commandFileName, string commandToRun, string workingDirectory)
{
string result;
if (!string.IsNullOrEmpty(commandFileName))
File.WriteAllText(Path.Combine(workingDirectory, commandFileName), commandToRun);
if (string.IsNullOrEmpty(workingDirectory))
workingDirectory = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory());
ProcessStartInfo processStartInfo = new()
{
FileName = "cmd",
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
WorkingDirectory = workingDirectory
};
Process? process = Process.Start(processStartInfo) ?? throw new Exception("Process should not be null.");
process.StandardInput.WriteLine($"{commandToRun} & exit");
process.WaitForExit();
result = $"{process.StandardOutput.ReadToEnd()}{Environment.NewLine}{process.StandardError.ReadToEnd()}{Environment.NewLine}{process.ExitCode}";
return result;
}
}

View File

@ -34,6 +34,7 @@ internal static class HelperSaveOrCopyContents
log.LogInformation("{empty}", string.Empty);
continue;
}
#pragma warning disable IDE0072
string fileName = dfb switch
{
ConsoleKey.D => "Directories",
@ -41,6 +42,7 @@ internal static class HelperSaveOrCopyContents
ConsoleKey.B => "Both",
_ => throw new NotSupportedException(),
};
#pragma warning restore IDE0072
string filePathAndName = Path.Combine(parentDirectory, $"{fileName}.txt");
if (dfb == ConsoleKey.F)
collection = Directory.GetFiles(argsZero, "*", searchOption).ToList();
@ -79,7 +81,7 @@ internal static class HelperSaveOrCopyContents
foreach (string file in files)
{
fileName = Path.GetFileName(file);
if (fileName == fileName.ToLower())
if (fileName.Equals(fileName, StringComparison.CurrentCultureIgnoreCase))
continue;
File.Move(file, file.ToLower());
filesRenamed++;

View File

@ -0,0 +1,100 @@
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
namespace File_Folder_Helper.Helpers;
public static class RijndaelEncryption
{ // cSpell:disable
/// <summary>
/// Change the input key GUID when you use this code in your own program.
/// Keep this input key very safe and prevent someone from decoding it some way!!
/// Generated 2021-08-10
/// </summary>
internal const string _InputKey = "970CCEF6-4307-4F6A-9AC8-377DADB889BD";
/// <summary>
/// Encrypt the given text and give the byte array back as a BASE64 string
/// </summary>
/// <param name="text">The text to encrypt</param>
/// <param name="salt">The password salt</param>
/// <returns>The encrypted text</returns>
public static string Encrypt(string text, string salt)
{
string result;
if (string.IsNullOrEmpty(text))
throw new ArgumentNullException(nameof(text));
#pragma warning disable SYSLIB0022
RijndaelManaged aesAlg = NewRijndaelManaged(salt);
#pragma warning restore
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
MemoryStream msEncrypt = new();
using (CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write))
using (StreamWriter swEncrypt = new(csEncrypt))
swEncrypt.Write(text);
result = Convert.ToBase64String(msEncrypt.ToArray());
return result;
}
/// <summary>
/// Checks if a string is base64 encoded
/// </summary>
/// <param name="base64String">The base64 encoded string</param>
/// <returns></returns>
public static bool IsBase64String(string base64String)
{
bool result;
base64String = base64String.Trim();
#pragma warning restore
result = (base64String.Length % 4 == 0) && Regex.IsMatch(base64String, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None);
#pragma warning restore
return result;
}
/// <summary>
/// Decrypts the given text
/// </summary>
/// <param name="cipherText">The encrypted BASE64 text</param>
/// <param name="salt">The password salt</param>
/// <returns>De gedecrypte text</returns>
public static string Decrypt(string cipherText, string salt)
{
if (string.IsNullOrEmpty(cipherText))
throw new ArgumentNullException(nameof(cipherText));
if (!IsBase64String(cipherText))
throw new Exception("The cipherText input parameter is not base64 encoded");
string text;
#pragma warning disable SYSLIB0022
RijndaelManaged aesAlg = NewRijndaelManaged(salt);
#pragma warning restore
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
byte[] cipher = Convert.FromBase64String(cipherText);
using (MemoryStream msDecrypt = new(cipher))
{
using CryptoStream csDecrypt = new(msDecrypt, decryptor, CryptoStreamMode.Read);
using StreamReader srDecrypt = new(csDecrypt);
text = srDecrypt.ReadToEnd();
}
return text;
}
/// <summary>
/// Create a new RijndaelManaged class and initialize it
/// </summary>
/// <param name="salt">The password salt</param>
/// <returns></returns>
#pragma warning disable SYSLIB0022, SYSLIB0041, CA5379
private static RijndaelManaged NewRijndaelManaged(string salt)
{
ArgumentNullException.ThrowIfNull(salt);
byte[] saltBytes = Encoding.ASCII.GetBytes(salt);
Rfc2898DeriveBytes key = new(_InputKey, saltBytes);
RijndaelManaged aesAlg = new();
#pragma warning restore
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);
return aesAlg;
}
}