This commit is contained in:
TSRBerry 2022-12-16 22:02:37 +00:00 committed by GitHub
commit 87db725308
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 186 additions and 19 deletions

View file

@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using Ryujinx.CustomTasks.SyntaxWalker; using Ryujinx.CustomTasks.SyntaxWalker;
using Ryujinx.CustomTasks.Helper; using Ryujinx.CustomTasks.Helper;
using System;
using System.Linq;
using Task = Microsoft.Build.Utilities.Task; using Task = Microsoft.Build.Utilities.Task;
namespace Ryujinx.CustomTasks namespace Ryujinx.CustomTasks
@ -15,7 +17,7 @@ namespace Ryujinx.CustomTasks
private const string InterfaceFileName = "IArray.g.cs"; private const string InterfaceFileName = "IArray.g.cs";
private const string ArraysFileName = "Arrays.g.cs"; private const string ArraysFileName = "Arrays.g.cs";
private readonly List<string> _outputFiles = new List<string>(); private readonly HashSet<string> _outputFiles = new HashSet<string>();
[Required] [Required]
public string ArrayNamespace { get; set; } public string ArrayNamespace { get; set; }
@ -24,7 +26,19 @@ namespace Ryujinx.CustomTasks
public string OutputPath { get; set; } public string OutputPath { get; set; }
[Required] [Required]
public ITaskItem[] InputFiles { get; set; } public bool ScanSolution { get; set; }
[Required]
public string SolutionDir { get; set; }
[Required]
public string ProjectDir { get; set; }
[Required]
public string NugetPackagePath { get; set; }
[Required]
public string TargetFramework { get; set; }
[Output] [Output]
public string[] OutputFiles { get; set; } public string[] OutputFiles { get; set; }
@ -52,13 +66,164 @@ namespace Ryujinx.CustomTasks
return size; return size;
} }
private void AddGeneratedSource(string filePath, string content) private string[] GetProjectFiles()
{ {
File.WriteAllText(filePath, content); if (ScanSolution)
_outputFiles.Add(filePath); {
return Directory.GetFiles(SolutionDir, "*.csproj", SearchOption.AllDirectories);
}
else
{
return Directory.GetFiles(ProjectDir, "*.csproj", SearchOption.TopDirectoryOnly);
}
} }
private ICollection<int> GetArraySizes(string itemPath) private bool TryGetNugetAssemblyPath(string package, string version, out string assemblyPath)
{
if (string.IsNullOrEmpty(version))
{
assemblyPath = "";
return false;
}
string basePath = Path.Combine(NugetPackagePath, package.ToLower(), version, "lib");
string filePath;
if (Directory.Exists(Path.Combine(basePath, TargetFramework)))
{
filePath = Directory.GetFiles(Path.Combine(basePath, TargetFramework), "*.dll", SearchOption.TopDirectoryOnly).FirstOrDefault();
if (string.IsNullOrEmpty(filePath))
{
assemblyPath = "";
return false;
}
assemblyPath = filePath;
return true;
}
string[] frameworks = Directory.GetDirectories(basePath);
List<string> standardList = frameworks.Where(framework => framework.Contains("netstandard")).ToList();
if (standardList.Count > 0)
{
filePath = Directory.GetFiles(Path.Combine(basePath, standardList.Max()), "*.dll", SearchOption.TopDirectoryOnly).FirstOrDefault();
if (string.IsNullOrEmpty(filePath))
{
assemblyPath = "";
return false;
}
assemblyPath = filePath;
return true;
}
assemblyPath = Directory.GetFiles(Path.Combine(basePath, frameworks.Max()), "*.dll", SearchOption.TopDirectoryOnly).FirstOrDefault();
return !string.IsNullOrEmpty(assemblyPath);
}
private string GetAttributeValue(string line, string attribute)
{
int startIndex = line.IndexOf($"{attribute}=\"", StringComparison.OrdinalIgnoreCase) + 1;
int length = line.Substring(startIndex).IndexOf("\"", StringComparison.OrdinalIgnoreCase);
return line.Substring(startIndex, length);
}
private string GetCentralPackageVersion(string packageName)
{
string packagePropsPath = Path.Combine(SolutionDir, "Directory.Packages.props");
if (!File.Exists(packagePropsPath))
{
return "";
}
foreach (var line in File.ReadLines(packagePropsPath))
{
string trimmedLine = line.Trim();
if (trimmedLine.StartsWith("<PackageVersion") && trimmedLine.Contains(packageName))
{
return GetAttributeValue(trimmedLine, "Version");
}
}
return "";
}
private HashSet<string> GetReferences(string projectPath)
{
bool isItemGroup = false;
HashSet<string> references = new HashSet<string>();
// Filter for PackageReference and ProjectReference
foreach (string line in File.ReadLines(projectPath))
{
string trimmedLine = line.Trim();
if (!isItemGroup && trimmedLine.Contains("<ItemGroup>"))
{
isItemGroup = true;
}
switch (isItemGroup)
{
case true when trimmedLine.Contains("<PackageReference"):
string package = GetAttributeValue(trimmedLine, "Include");
string version = !trimmedLine.Contains("Version")
? GetCentralPackageVersion(package)
: GetAttributeValue(trimmedLine, "Version");
if (TryGetNugetAssemblyPath(package, version, out string filePath))
{
references.Add(filePath);
}
else
{
throw new DllNotFoundException($"Couldn't find dll for '{package}' with version {version}");
}
break;
case true when trimmedLine.StartsWith("<ProjectReference", StringComparison.OrdinalIgnoreCase):
references.Add(GetAttributeValue(trimmedLine, "Include"));
break;
case true when trimmedLine.StartsWith("</ItemGroup>", StringComparison.OrdinalIgnoreCase):
isItemGroup = false;
break;
}
}
return references;
}
private void AddGeneratedSource(string filePath, string content)
{
bool addToOutputFiles = true;
if (File.Exists(filePath))
{
File.Delete(filePath);
addToOutputFiles = false;
}
File.WriteAllText(filePath, content);
if (addToOutputFiles)
{
_outputFiles.Add(filePath);
}
}
private HashSet<int> GetArraySizes(string itemPath)
{ {
Log.LogMessage(MessageImportance.Low, $"Searching for StructArray types in: {itemPath}"); Log.LogMessage(MessageImportance.Low, $"Searching for StructArray types in: {itemPath}");
@ -173,19 +338,14 @@ namespace Ryujinx.CustomTasks
string arraysFilePath = Path.Combine(OutputPath, ArraysFileName); string arraysFilePath = Path.Combine(OutputPath, ArraysFileName);
List<int> arraySizes = new List<int>(); List<int> arraySizes = new List<int>();
File.Delete(interfaceFilePath); foreach (var item in Directory.EnumerateFiles(ScanSolution ? SolutionDir: ProjectDir, "*.cs", SearchOption.AllDirectories))
File.Delete(arraysFilePath);
foreach (var item in InputFiles)
{ {
string fullPath = item.GetMetadata("FullPath"); if (item.EndsWith(".g.cs") || item.Contains(Path.Combine("obj","Debug")) || item.Contains(Path.Combine("obj", "Release")))
if (fullPath.EndsWith(".g.cs") || fullPath.Contains(Path.Combine("obj","Debug")) || fullPath.Contains(Path.Combine("obj", "Release")))
{ {
continue; continue;
} }
foreach (int size in GetArraySizes(fullPath)) foreach (int size in GetArraySizes(item))
{ {
if (!arraySizes.Contains(size)) if (!arraySizes.Contains(size))
{ {

View file

@ -6,7 +6,7 @@ namespace Ryujinx.CustomTasks.SyntaxWalker
{ {
class ArraySizeCollector : CSharpSyntaxWalker class ArraySizeCollector : CSharpSyntaxWalker
{ {
public ICollection<int> ArraySizes { get; } = new List<int>(); public HashSet<int> ArraySizes { get; } = new HashSet<int>();
private void AddArrayString(string name) private void AddArrayString(string name)
{ {
@ -17,7 +17,7 @@ namespace Ryujinx.CustomTasks.SyntaxWalker
string rawArrayType = name.Split('<')[0]; string rawArrayType = name.Split('<')[0];
if (int.TryParse(rawArrayType.Substring(5), out int size) && !ArraySizes.Contains(size)) if (int.TryParse(rawArrayType.Substring(5), out int size))
{ {
ArraySizes.Add(size); ArraySizes.Add(size);
} }

View file

@ -3,16 +3,23 @@
<!-- Task: GenerateArrays --> <!-- Task: GenerateArrays -->
<!-- Defining all sources files of the current project for the input parameter --> <!-- Assign default values -->
<PropertyGroup>
<ArrayScanSolution Condition="'$(ArrayScanSolution)' == ''">false</ArrayScanSolution>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ArrayInputFiles Condition="'$(ArrayInputFiles)' == ''" Include="$(MSBuildProjectDirectory)\**\*.cs" /> <ArrayInputFiles Condition="'$(ArrayScanSolution)' == 'false'" Include="$(MSBuildProjectDirectory)\**\*.cs" />
<ArrayInputFiles Condition="'$(ArrayScanSolution)' == 'true'" Include="$(SolutionDir)\**\*.cs" />
</ItemGroup> </ItemGroup>
<!--A target that generates code, which is executed before the compilation--> <!--A target that generates code, which is executed before the compilation-->
<!-- TODO: Make "Outputs" more generic --> <!-- TODO: Make "Outputs" more generic -->
<Target Name="BeforeCompile" Inputs="@(ArrayInputFiles)" Outputs="$(ArrayOutputPath)\Arrays.g.cs;$(ArrayOutputPath)\IArray.g.cs"> <Target Name="BeforeCompile" Inputs="@(ArrayInputFiles)" Outputs="$(ArrayOutputPath)\Arrays.g.cs;$(ArrayOutputPath)\IArray.g.cs">
<!--Calling our custom task --> <!--Calling our custom task -->
<GenerateArrays ArrayNamespace="$(ArrayNamespace)" InputFiles="@(ArrayInputFiles)" OutputPath="$(ArrayOutputPath)"> <GenerateArrays ArrayNamespace="$(ArrayNamespace)" ScanSolution="$(ArrayScanSolution)" OutputPath="$(ArrayOutputPath)"
SolutionDir="$(SolutionDir)" ProjectDir="$(MSBuildProjectDirectory)" NugetPackagePath="$(NuGetPackageRoot)"
TargetFramework="$(TargetFramework)">
<!--Our generated files are included to be compiled--> <!--Our generated files are included to be compiled-->
<Output TaskParameter="OutputFiles" ItemName="Compile" /> <Output TaskParameter="OutputFiles" ItemName="Compile" />
</GenerateArrays> </GenerateArrays>