Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for nuget package with multiple Roslyn version analyzers #616

Merged
merged 11 commits into from
Mar 3, 2024
60 changes: 59 additions & 1 deletion src/NuGetForUnity/Editor/NugetAssetPostprocessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,32 @@ namespace NugetForUnity
/// </summary>
public class NugetAssetPostprocessor : AssetPostprocessor
{
private const string MaxSupportedRoslynVersion =
#if UNITY_2022_3_OR_NEWER && !UNITY_2022_3_1 && !UNITY_2022_3_2 && !UNITY_2022_3_3 && !UNITY_2022_3_3 && !UNITY_2022_3_4 && !UNITY_2022_3_5 && !UNITY_2022_3_6 && !UNITY_2022_3_7 && !UNITY_2022_3_8 && !UNITY_2022_3_9 && !UNITY_2022_3_10 && !UNITY_2022_3_11
JoC0de marked this conversation as resolved.
Show resolved Hide resolved
"4.3.0";
#elif UNITY_2022_2_OR_NEWER
"4.1.0";
#elif UNITY_2021_2_OR_NEWER
"3.8.0";
#else
"";
#endif

/// <summary>
/// Folder used to store Roslyn-Analyzers inside NuGet packages.
/// </summary>
private const string AnalyzersFolderName = "analyzers";

/// <summary>
/// Folder of root before the version of analyzers was split.
/// </summary>
private static readonly string AnalyzersRoslynVersionsFolderName = Path.Combine(AnalyzersFolderName, "dotnet");

/// <summary>
/// Prefix for roslyn versioning of dll asset path.
/// </summary>
private static readonly string AnalyzersRoslynVersionSubFolderPrefix = Path.Combine(AnalyzersRoslynVersionsFolderName, "roslyn");

/// <summary>
/// Used to mark an asset as already processed by this class.
/// </summary>
Expand Down Expand Up @@ -180,6 +201,21 @@ private static string GetNuGetRepositoryPath()
return ConfigurationManager.NugetConfigFile.RepositoryPath + Path.DirectorySeparatorChar;
}

[CanBeNull]
private static string GetRoslynVersionNumberFromAnalyzerPath(string analyzerAssetPath)
{
var versionPrefixIndex = analyzerAssetPath.IndexOf(AnalyzersRoslynVersionSubFolderPrefix, StringComparison.Ordinal);
if (versionPrefixIndex < 0)
{
return null;
}

var startIndex = versionPrefixIndex + AnalyzersRoslynVersionSubFolderPrefix.Length;
var separatorIndex = analyzerAssetPath.IndexOf(Path.DirectorySeparatorChar, startIndex);
var length = separatorIndex >= 0 ? separatorIndex - startIndex : analyzerAssetPath.Length - startIndex;
return analyzerAssetPath.Substring(startIndex, length);
}

private static void ModifyImportSettingsOfRoslynAnalyzer([NotNull] PluginImporter plugin, bool reimport)
{
plugin.SetCompatibleWithAnyPlatform(false);
Expand All @@ -189,7 +225,29 @@ private static void ModifyImportSettingsOfRoslynAnalyzer([NotNull] PluginImporte
plugin.SetExcludeFromAnyPlatform(platform, false);
}

AssetDatabase.SetLabels(plugin, new[] { RoslynAnalyzerLabel, ProcessedLabel });
var enableRoslynAnalyzer = true;

// The nuget package can contain analyzers for multiple Roslyn versions.
// In that case, for the same package, the most recent version must be chosen out of those available for the current Unity version.
var assetPath = Path.GetFullPath(plugin.assetPath);
var assetRoslynVersion = GetRoslynVersionNumberFromAnalyzerPath(assetPath);
if (assetRoslynVersion != null)
{
var versionPrefixIndex = assetPath.IndexOf(AnalyzersRoslynVersionsFolderName, StringComparison.Ordinal);
var analyzersVersionsRoot = Path.Combine(assetPath.Substring(0, versionPrefixIndex), AnalyzersRoslynVersionsFolderName);
var analyzersFolders = Directory.GetDirectories(analyzersVersionsRoot);
var enabledRoslynVersions = analyzersFolders.Select(GetRoslynVersionNumberFromAnalyzerPath)
.Where(version => version != null && string.CompareOrdinal(version, MaxSupportedRoslynVersion) <= 0)
JoC0de marked this conversation as resolved.
Show resolved Hide resolved
.ToArray();

// If most recent valid analyzers exist elsewhere, remove label `RoslynAnalyzer`
if (!enabledRoslynVersions.Contains(assetRoslynVersion) || string.CompareOrdinal(assetRoslynVersion, enabledRoslynVersions.Max()) < 0)
{
enableRoslynAnalyzer = false;
}
}

AssetDatabase.SetLabels(plugin, enableRoslynAnalyzer ? new[] { RoslynAnalyzerLabel, ProcessedLabel } : new[] { ProcessedLabel });

if (reimport)
{
Expand Down
Loading