Skip to content

Commit

Permalink
Validation Project v2 (#444)
Browse files Browse the repository at this point in the history
Refactor of the Validation System for more ease of use in the future.
The project now builds a standalone executable and executes it before
the main project is built or published.
Since it is now a standalone executable we are also able to use .NET
Core features as we are no longer locked to netstandard.

The project currently includes 1 task, LocalesValidationTask, that will
check if the locales.json file has any of the following issues:
The json is invalid.
The json has locales with missing languages.
The json has locales with langauges that are just duplicates of the
en_US field.

If the project is built or published locally it will also fix any
missing languages or duplicate fields.

---------

Co-authored-by: Evan Husted <[email protected]>
Co-authored-by: Evan Husted <[email protected]>
  • Loading branch information
3 people authored Dec 30, 2024
1 parent 699e196 commit b2e1e55
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 239 deletions.
5 changes: 2 additions & 3 deletions Ryujinx.sln
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,12 @@ Global
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
73 changes: 0 additions & 73 deletions src/Ryujinx.BuildValidationTasks/LocaleValidationTask.cs

This file was deleted.

117 changes: 117 additions & 0 deletions src/Ryujinx.BuildValidationTasks/LocalesValidationTask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text.Json;
using System.Text.Encodings.Web;

namespace Ryujinx.BuildValidationTasks
{
public class LocalesValidationTask : ValidationTask
{
public LocalesValidationTask() { }

public bool Execute(string projectPath, bool isGitRunner)
{
Console.WriteLine("Running Locale Validation Task...");

string path = projectPath + "src/Ryujinx/Assets/locales.json";
string data;

using (StreamReader sr = new(path))
{
data = sr.ReadToEnd();
}

LocalesJson json;

if (isGitRunner && data.Contains("\r\n"))
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, build locally to fix...");

try
{
json = JsonSerializer.Deserialize<LocalesJson>(data);

}
catch (JsonException e)
{
throw new JsonException(e.Message); //shorter and easier stacktrace
}



bool encounteredIssue = false;

for (int i = 0; i < json.Locales.Count; i++)
{
LocalesEntry locale = json.Locales[i];

foreach (string langCode in json.Languages.Where(lang => !locale.Translations.ContainsKey(lang)))
{
encounteredIssue = true;

if (!isGitRunner)
{
locale.Translations.Add(langCode, string.Empty);
Console.WriteLine($"Added '{langCode}' to Locale '{locale.ID}'");
}
else
{
Console.WriteLine($"Missing '{langCode}' in Locale '{locale.ID}'!");
}
}

foreach (string langCode in json.Languages.Where(lang => locale.Translations.ContainsKey(lang) && lang != "en_US" && locale.Translations[lang] == locale.Translations["en_US"]))
{
encounteredIssue = true;

if (!isGitRunner)
{
locale.Translations[langCode] = string.Empty;
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'! Resetting it...");
}
else
{
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'!");
}
}

locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
json.Locales[i] = locale;
}

if (isGitRunner && encounteredIssue)
throw new JsonException("1 or more locales are invalid!");

JsonSerializerOptions jsonOptions = new JsonSerializerOptions()
{
WriteIndented = true,
NewLine = "\n",
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

string jsonString = JsonSerializer.Serialize(json, jsonOptions);

using (StreamWriter sw = new(path))
{
sw.Write(jsonString);
}

Console.WriteLine("Finished Locale Validation Task!");

return true;
}

struct LocalesJson
{
public List<string> Languages { get; set; }
public List<LocalesEntry> Locales { get; set; }
}

struct LocalesEntry
{
public string ID { get; set; }
public Dictionary<string, string> Translations { get; set; }
}
}
}
37 changes: 37 additions & 0 deletions src/Ryujinx.BuildValidationTasks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.IO;
using System.Linq;

namespace Ryujinx.BuildValidationTasks
{
public class Program
{
static void Main(string[] args)
{
// Display the number of command line arguments.
if (args.Length == 0)
throw new ArgumentException("Error: too few arguments!");

string path = args[0];

if (string.IsNullOrEmpty(path))
throw new ArgumentException("Error: path is null or empty!");

if (!Path.Exists(path))
throw new FileLoadException($"path {{{path}}} does not exist!");

path = Path.GetFullPath(path);

if (!Directory.GetDirectories(path).Contains($"{path}src"))
throw new FileLoadException($"path {{{path}}} is not a valid ryujinx project!");

bool isGitRunner = path.Contains("runner") || path.Contains("D:\\a\\Ryujinx\\Ryujinx");
if (isGitRunner)
Console.WriteLine("Is Git Runner!");

// Run tasks
// Pass extra info needed in the task constructors
new LocalesValidationTask().Execute(path, isGitRunner);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" />
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
<Target Name="PostBuildTarget" AfterTargets="AfterBuild">
<Message Text="Running Validation Project" Importance="high" />

<UsingTask TaskName="Ryujinx.BuildValidationTasks.LocaleValidationTask" TaskFactory="TaskHostFactory" AssemblyFile="$(OutDir)Ryujinx.BuildValidationTasks.dll" />

<Target Name="LocalesJsonValidation" AfterTargets="AfterRebuild">
<LocaleValidationTask />
<Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\"
Command="dotnet Ryujinx.BuildValidationTasks.dll &quot;$(ProjectDir)..\..\\&quot;"
ConsoleToMsBuild="true"
/>
</Target>

</Project>
</Project>
7 changes: 7 additions & 0 deletions src/Ryujinx.BuildValidationTasks/ValidationTask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Ryujinx.BuildValidationTasks
{
public interface ValidationTask
{
public bool Execute(string projectPath, bool isGitRunner);
}
}
Loading

0 comments on commit b2e1e55

Please sign in to comment.