Skip to content

Commit

Permalink
Properly filter assemblies compatible with the Roslyn version support…
Browse files Browse the repository at this point in the history
…ed by Unity (#255)

* Properly filter assemblies compatible with the Roslyn version supported by Unity

* WIP

* WIP
  • Loading branch information
bdovaz authored Sep 30, 2023
1 parent 9fc7ce1 commit faf3d4e
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 14 deletions.
49 changes: 49 additions & 0 deletions src/UnityNuGet.Tests/NuGetHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,55 @@ namespace UnityNuGet.Tests
{
public class NuGetHelperTests
{
[Test]
[TestCase("analyzers/dotnet/roslyn3.8/cs/Test.resources.dll")]
[TestCase("analyzers/dotnet/roslyn3.8/Test.resources.dll")]
[TestCase("analyzers/dotnet/cs/Test.resources.dll")]
[TestCase("analyzers/dotnet/Test.resources.dll")]
[TestCase("analyzers/Test.resources.dll")]
public void IsApplicableAnalyzerResource_Valid(string input)
{
Assert.True(NuGetHelper.IsApplicableAnalyzerResource(input));
}

[Test]
[TestCase("analyzers/dotnet/roslyn3.8/vb/cs/Test.resources.dll")]
[TestCase("analyzers/dotnet/roslyn3.8/cs/Test.dll")]
[TestCase("analyzers/dotnet/roslyn3.8/Test.dll")]
[TestCase("analyzers/dotnet/vb/Test.dll")]
[TestCase("analyzers/dotnet/cs/Test.dll")]
[TestCase("analyzers/dotnet/Test.dll")]
[TestCase("analyzers/Test.dll")]
public void IsApplicableAnalyzerResource_Invalid(string input)
{
Assert.False(NuGetHelper.IsApplicableAnalyzerResource(input));
}

// Examples:
// Meziantou.Analyzer -> analyzers/dotnet/roslyn3.8/cs/*
// Microsoft.Unity.Analyzers -> analyzers/dotnet/cs/*
// Microsoft.VisualStudio.Threading.Analyzers -> analyzers/cs/*
// SonarAnalyzer.CSharp -> analyzers/*
// StrongInject -> analyzers/dotnet/cs/* + analyzers/dotnet/roslyn3.8/cs/*
[Test]
[TestCase("analyzers/dotnet/roslyn3.8/cs/Test.dll")]
[TestCase("analyzers/dotnet/roslyn3.8/Test.dll")]
[TestCase("analyzers/dotnet/cs/Test.dll")]
[TestCase("analyzers/dotnet/Test.dll")]
[TestCase("analyzers/Test.dll")]
public void IsApplicableUnitySupportedRoslynVersionFolder_Valid(string input)
{
Assert.True(NuGetHelper.IsApplicableUnitySupportedRoslynVersionFolder(input));
}

[Test]
[TestCase("analyzers/dotnet/roslyn4.0/cs/Test.dll")]
[TestCase("analyzers/dotnet/roslyn4.0/Test.dll")]
public void IsApplicableUnitySupportedRoslynVersionFolder_Invalid(string input)
{
Assert.False(NuGetHelper.IsApplicableUnitySupportedRoslynVersionFolder(input));
}

[Test]
public void GetCompatiblePackageDependencyGroups_SpecificSingleFramework()
{
Expand Down
67 changes: 66 additions & 1 deletion src/UnityNuGet/NuGetHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using NuGet.Protocol.Core.Types;
Expand All @@ -8,6 +10,69 @@ namespace UnityNuGet
{
static class NuGetHelper
{
// https://learn.microsoft.com/en-us/visualstudio/extensibility/roslyn-version-support
private static readonly Regex roslynVersionRegex = new(@"/roslyn(\d+)\.(\d+)\.?(\d*)/");

// https://docs.unity3d.com/Manual/roslyn-analyzers.html
private static readonly Version unityRoslynSupportedVersion = new(3, 8, 0);

// https://github.com/dotnet/sdk/blob/2838d93742658300698b2194882d57fd978fb168/src/Tasks/Microsoft.NET.Build.Tasks/NuGetUtils.NuGet.cs#L50
public static bool IsApplicableAnalyzer(string file) => IsApplicableAnalyzer(file, "C#");

private static bool IsApplicableAnalyzer(string file, string projectLanguage)
{
// This logic is preserved from previous implementations.
// See https://github.com/NuGet/Home/issues/6279#issuecomment-353696160 for possible issues with it.
bool IsAnalyzer()
{
return file.StartsWith("analyzers", StringComparison.Ordinal)
&& file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)
&& !file.EndsWith(".resources.dll", StringComparison.OrdinalIgnoreCase);
}

bool CS() => file.Contains("/cs/", StringComparison.OrdinalIgnoreCase);
bool VB() => file.Contains("/vb/", StringComparison.OrdinalIgnoreCase);

bool FileMatchesProjectLanguage()
{
return projectLanguage switch
{
"C#" => CS() || !VB(),
"VB" => VB() || !CS(),
_ => false,
};
}

return IsAnalyzer() && FileMatchesProjectLanguage();
}

public static bool IsApplicableAnalyzerResource(string file)
{
bool IsResource()
{
return file.StartsWith("analyzers", StringComparison.Ordinal)
&& file.EndsWith(".resources.dll", StringComparison.OrdinalIgnoreCase);
}

bool CS() => file.Contains("/cs/", StringComparison.OrdinalIgnoreCase);
bool VB() => file.Contains("/vb/", StringComparison.OrdinalIgnoreCase);

// Czech locale is cs, catch /vb/cs/
return IsResource() && ((!CS() && !VB()) || (CS() && !VB()));
}

public static bool IsApplicableUnitySupportedRoslynVersionFolder(string file)
{
var roslynVersionMatch = roslynVersionRegex.Match(file);

bool hasRoslynVersionFolder = roslynVersionMatch.Success;
bool hasUnitySupportedRoslynVersionFolder = hasRoslynVersionFolder &&
int.Parse(roslynVersionMatch.Groups[1].Value) == unityRoslynSupportedVersion.Major &&
int.Parse(roslynVersionMatch.Groups[2].Value) == unityRoslynSupportedVersion.Minor;

return !hasRoslynVersionFolder || hasUnitySupportedRoslynVersionFolder;
}

public static IEnumerable<(FrameworkSpecificGroup, RegistryTargetFramework)> GetClosestFrameworkSpecificGroups(IEnumerable<FrameworkSpecificGroup> versions, IEnumerable<RegistryTargetFramework> targetFrameworks)
{
var result = new List<(FrameworkSpecificGroup, RegistryTargetFramework)>();
Expand Down
35 changes: 22 additions & 13 deletions src/UnityNuGet/RegistryCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class RegistryCache
public static readonly bool IsRunningOnAzure = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"));

// Change this version number if the content of the packages are changed by an update of this class
private const string CurrentRegistryVersion = "1.7.0";
private const string CurrentRegistryVersion = "1.8.0";

private static readonly Encoding Utf8EncodingNoBom = new UTF8Encoding(false, false);
private readonly string _rootPersistentFolder;
Expand Down Expand Up @@ -260,7 +260,6 @@ private async Task BuildInternal()
var currentVersion = packageIdentity.Version;
string npmCurrentVersion = GetNpmVersion(currentVersion);


if (packageEntry.Version == null || !packageEntry.Version.Satisfies(packageMeta.Identity.Version))
{
continue;
Expand Down Expand Up @@ -596,12 +595,11 @@ RegistryEntry packageEntry
{
var packageFiles = await packageReader.GetItemsAsync(PackagingConstants.Folders.Analyzers, CancellationToken.None);

var analyzerFiles = packageFiles.SelectMany(p => p.Items).Where(p => p.StartsWith("analyzers/dotnet/cs")).ToArray();

if (analyzerFiles.Length == 0)
{
analyzerFiles = packageFiles.SelectMany(p => p.Items).Where(p => p.StartsWith("analyzers")).ToArray();
}
// https://learn.microsoft.com/en-us/nuget/guides/analyzers-conventions#analyzers-path-format
var analyzerFiles = packageFiles
.SelectMany(p => p.Items)
.Where(p => NuGetHelper.IsApplicableUnitySupportedRoslynVersionFolder(p) && (NuGetHelper.IsApplicableAnalyzer(p) || NuGetHelper.IsApplicableAnalyzerResource(p)))
.ToArray();

var createdDirectoryList = new List<string>();

Expand Down Expand Up @@ -640,11 +638,22 @@ RegistryEntry packageEntry

if (fileExtension == ".dll")
{
meta = UnityMeta.GetMetaForDll(
GetStableGuid(identity, fileInUnityPackage),
new PlatformDefinition(UnityOs.AnyOs, UnityCpu.None, isEditorConfig: false),
new string[] { "RoslynAnalyzer" },
Array.Empty<string>());
if (NuGetHelper.IsApplicableAnalyzer(analyzerFile))
{
meta = UnityMeta.GetMetaForDll(
GetStableGuid(identity, fileInUnityPackage),
new PlatformDefinition(UnityOs.AnyOs, UnityCpu.None, isEditorConfig: false),
new string[] { "RoslynAnalyzer" },
Array.Empty<string>());
}
else
{
meta = UnityMeta.GetMetaForDll(
GetStableGuid(identity, fileInUnityPackage),
new PlatformDefinition(UnityOs.AnyOs, UnityCpu.None, isEditorConfig: false),
Array.Empty<string>(),
Array.Empty<string>());
}
}
else
{
Expand Down

0 comments on commit faf3d4e

Please sign in to comment.