mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 23:26:40 -08:00
Some utility scripts for C# and VB.NET ports
This commit is contained in:
10
00_Utilities/DotnetUtils/DotnetUtils/DotnetUtils.csproj
Normal file
10
00_Utilities/DotnetUtils/DotnetUtils/DotnetUtils.csproj
Normal 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>
|
||||
27
00_Utilities/DotnetUtils/DotnetUtils/Extensions.cs
Normal file
27
00_Utilities/DotnetUtils/DotnetUtils/Extensions.cs
Normal 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 /
|
||||
}
|
||||
}
|
||||
8
00_Utilities/DotnetUtils/DotnetUtils/Globals.cs
Normal file
8
00_Utilities/DotnetUtils/DotnetUtils/Globals.cs
Normal 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") }
|
||||
};
|
||||
}
|
||||
51
00_Utilities/DotnetUtils/DotnetUtils/PortInfo.cs
Normal file
51
00_Utilities/DotnetUtils/DotnetUtils/PortInfo.cs
Normal 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
22
00_Utilities/DotnetUtils/DotnetUtils/PortInfos.cs
Normal file
22
00_Utilities/DotnetUtils/DotnetUtils/PortInfos.cs
Normal 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;
|
||||
}
|
||||
163
00_Utilities/DotnetUtils/DotnetUtils/Program.cs
Normal file
163
00_Utilities/DotnetUtils/DotnetUtils/Program.cs
Normal 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}");
|
||||
}
|
||||
Reference in New Issue
Block a user