Some utility scripts for C# and VB.NET ports

This commit is contained in:
Zev Spitz
2022-01-13 16:24:46 +02:00
parent d2cc1389a0
commit baf5d3750a
8 changed files with 474 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,27 @@
using System.Diagnostics.CodeAnalysis;
namespace DotnetUtils;
public static class Extensions {
public static IEnumerable<TResult> SelectT<T1, T2, TResult>(this IEnumerable<(T1, T2)> src, Func<T1, T2, TResult> selector) =>
src.Select(x => selector(x.Item1, x.Item2));
public static IEnumerable<TResult> SelectT<T1, T2, T3, TResult>(this IEnumerable<(T1, T2, T3)> src, Func<T1, T2, T3, TResult> selector) =>
src.Select(x => selector(x.Item1, x.Item2, x.Item3));
public static IEnumerable<(T1, T2, int)> WithIndex<T1, T2>(this IEnumerable<(T1, T2)> src) => src.Select((x, index) => (x.Item1, x.Item2, index));
public static bool IsNullOrWhitespace([NotNullWhen(false)] this string? s) => string.IsNullOrWhiteSpace(s);
[return: NotNullIfNotNull("path")]
public static string? RelativePath(this string? path, string? rootPath) {
if (
path.IsNullOrWhitespace() ||
rootPath.IsNullOrWhitespace()
) { return path; }
var path1 = path.TrimEnd('\\');
rootPath = rootPath.TrimEnd('\\');
if (!path1.StartsWith(rootPath, StringComparison.InvariantCultureIgnoreCase)) { return path; }
return path1[(rootPath.Length + 1)..]; // ignore the initial /
}
}

View File

@@ -0,0 +1,8 @@
namespace DotnetUtils;
public static class Globals {
public static readonly Dictionary<string, (string codefileExtension, string projExtension)> LangData = new() {
{ "csharp", ("cs", "csproj") },
{ "vbnet", ("vb", "vbproj") }
};
}

View File

@@ -0,0 +1,51 @@
using System.Reflection;
using static System.IO.Directory;
using static System.IO.Path;
using static DotnetUtils.Globals;
namespace DotnetUtils;
public record PortInfo(
string FullPath, string FolderName, int Index, string GameName,
string LangPath, string Lang, string Ext, string ProjExt,
string[] CodeFiles, string[] Slns, string[] Projs
) {
private static readonly EnumerationOptions enumerationOptions = new() {
RecurseSubdirectories = true,
MatchType = MatchType.Simple,
MatchCasing = MatchCasing.CaseInsensitive
};
public static PortInfo? Create(string fullPath, string langKeyword) {
var folderName = GetFileName(fullPath);
var parts = folderName.Split('_', 2);
var index =
parts.Length > 0 && int.TryParse(parts[0], out var n) ?
n :
(int?)null;
var gameName =
parts.Length > 1 ?
parts[1].Replace("_", "") :
null;
if (index is 0 or null || gameName is null) { return null; }
var (ext, projExt) = LangData[langKeyword];
var langPath = Combine(fullPath, langKeyword);
var codeFiles =
GetFiles(langPath, $"*.{ext}", enumerationOptions)
.Where(x => !x.Contains("\\bin\\") && !x.Contains("\\obj\\"))
.ToArray();
return new PortInfo(
fullPath, folderName, index.Value, gameName,
langPath, langKeyword, ext, projExt,
codeFiles,
GetFiles(langPath, "*.sln", enumerationOptions),
GetFiles(langPath, $"*.{projExt}", enumerationOptions)
);
}
}

View File

@@ -0,0 +1,22 @@
using System.Reflection;
using static System.IO.Directory;
using static DotnetUtils.Globals;
namespace DotnetUtils;
public static class PortInfos {
public static readonly string Root;
static PortInfos() {
Root = GetParent(Assembly.GetEntryAssembly()!.Location)!.FullName;
Root = Root[..Root.IndexOf(@"\00_Utilities")];
Get = GetDirectories(Root)
.SelectMany(fullPath => LangData.Keys.Select(keyword => (fullPath, keyword)))
.SelectT((fullPath, keyword) => PortInfo.Create(fullPath, keyword))
.Where(x => x is not null)
.ToArray()!;
}
public static readonly PortInfo[] Get;
}

View File

@@ -0,0 +1,163 @@
using DotnetUtils;
using static System.Console;
using static System.IO.Path;
var infos = PortInfos.Get;
var actions = new (Action action, string description)[] {
(printInfos, "Output information -- solution, project, and code files"),
(missingSln, "Output missing sln"),
(unexpectedSlnName, "Output misnamed sln"),
(multipleSlns, "Output multiple sln files"),
(missingProj, "Output missing project file"),
(unexpectedProjName, "Output misnamed project files"),
(multipleProjs, "Output multiple project files")
};
foreach (var (_, description, index) in actions.WithIndex()) {
WriteLine($"{index}: {description}");
}
WriteLine();
actions[getChoice(actions.Length - 1)].action();
int getChoice(int maxValue) {
int result;
do {
Write("? ");
} while (!int.TryParse(ReadLine(), out result) || result < 0 || result > maxValue);
WriteLine();
return result;
}
void printSlns(PortInfo pi) {
switch (pi.Slns.Length) {
case 0:
WriteLine("No sln");
break;
case 1:
WriteLine($"Solution: {pi.Slns[0].RelativePath(pi.LangPath)}");
break;
case > 1:
WriteLine("Solutions:");
foreach (var sln in pi.Slns) {
Write(sln.RelativePath(pi.LangPath));
WriteLine();
}
break;
}
}
void printProjs(PortInfo pi) {
switch (pi.Projs.Length) {
case 0:
WriteLine("No project");
break;
case 1:
WriteLine($"Project: {pi.Projs[0].RelativePath(pi.LangPath)}");
break;
case > 1:
WriteLine("Projects:");
foreach (var proj in pi.Projs) {
Write(proj.RelativePath(pi.LangPath));
WriteLine();
}
break;
}
WriteLine();
}
void printInfos() {
foreach (var item in infos) {
WriteLine(item.LangPath);
WriteLine();
printSlns(item);
WriteLine();
printProjs(item);
WriteLine();
// get code files
foreach (var file in item.CodeFiles) {
WriteLine(file.RelativePath(item.LangPath));
}
WriteLine(new string('-', 50));
}
}
void missingSln() {
var data = infos.Where(x => !x.Slns.Any()).ToArray();
foreach (var item in data) {
WriteLine(item.LangPath);
}
WriteLine();
WriteLine($"Count: {data.Length}");
}
void unexpectedSlnName() {
var counter = 0;
foreach (var item in infos) {
if (!item.Slns.Any()) { continue; }
var expectedSlnName = $"{item.GameName}.sln";
if (item.Slns.Contains(Combine(item.LangPath, expectedSlnName))) { continue; }
counter += 1;
WriteLine(item.LangPath);
WriteLine($"Expected: {expectedSlnName}");
printSlns(item);
WriteLine();
}
WriteLine($"Count: {counter}");
}
void multipleSlns() {
var data = infos.Where(x => x.Slns.Length > 1).ToArray();
foreach (var item in data) {
WriteLine(item.LangPath);
printSlns(item);
}
WriteLine();
WriteLine($"Count: {data.Length}");
}
void missingProj() {
var data = infos.Where(x => !x.Projs.Any()).ToArray();
foreach (var item in data) {
WriteLine(item.LangPath);
}
WriteLine();
WriteLine($"Count: {data.Length}");
}
void unexpectedProjName() {
var counter = 0;
foreach (var item in infos) {
if (!item.Projs.Any()) { continue; }
var expectedProjName = $"{item.GameName}.{item.ProjExt}";
if (item.Projs.Contains(Combine(item.LangPath, expectedProjName))) { continue; }
counter += 1;
WriteLine(item.LangPath);
WriteLine($"Expected: {expectedProjName}");
printProjs(item);
WriteLine();
}
WriteLine($"Count: {counter}");
}
void multipleProjs() {
var data = infos.Where(x => x.Projs.Length > 1).ToArray();
foreach (var item in data) {
WriteLine(item.LangPath);
}
WriteLine();
WriteLine($"Count: {data.Length}");
}