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
72 changes: 70 additions & 2 deletions src/NuGetForUnity/Editor/NugetAssetPostprocessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ public class NugetAssetPostprocessor : AssetPostprocessor
/// </summary>
private const string AnalyzersFolderName = "analyzers";

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

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

/// <summary>
/// Used to mark an asset as already processed by this class.
/// </summary>
Expand Down Expand Up @@ -142,7 +152,7 @@ internal static void OnPostprocessAllAssets(

if (assetPathComponents.Length > 1 && assetPathComponents[1].Equals(AnalyzersFolderName, StringComparison.OrdinalIgnoreCase))
{
ModifyImportSettingsOfRoslynAnalyzer(plugin, reimport);
ModifyImportSettingsOfRoslynAnalyzer(plugin, assetPathComponents, reimport);
yield return ("RoslynAnalyzer", projectRelativeAssetPath, ResultStatus.Success);

yield break;
Expand All @@ -163,6 +173,12 @@ private static string[] GetPathComponents([NotNull] string path)
return path.Split(Path.DirectorySeparatorChar);
}

[NotNull]
private static string JoinPathComponents([NotNull] params string[] pathComponents)
popara96 marked this conversation as resolved.
Show resolved Hide resolved
{
return string.Join(Path.DirectorySeparatorChar.ToString(), pathComponents);
}

private static bool AssetIsDllInsideNuGetRepository([NotNull] string absoluteAssetPath, [NotNull] string absoluteRepositoryPath)
{
return absoluteAssetPath.StartsWith(absoluteRepositoryPath, PathHelper.PathComparisonType) &&
Expand All @@ -180,7 +196,21 @@ private static string GetNuGetRepositoryPath()
return ConfigurationManager.NugetConfigFile.RepositoryPath + Path.DirectorySeparatorChar;
}

private static void ModifyImportSettingsOfRoslynAnalyzer([NotNull] PluginImporter plugin, bool reimport)
[CanBeNull]
private static string GetRoslynVersionNumberFromAnalyzerPath(string analyzerAssetPath)
{
var versionPrefixIndex = analyzerAssetPath.IndexOf(AnalyzersRoslynVersionSubFolderPrefix, StringComparison.Ordinal);
if (versionPrefixIndex < 0)
{
return null;
}

return analyzerAssetPath.Substring(versionPrefixIndex + AnalyzersRoslynVersionSubFolderPrefix.Length)
.Split(Path.DirectorySeparatorChar)
hadashiA marked this conversation as resolved.
Show resolved Hide resolved
.First();
popara96 marked this conversation as resolved.
Show resolved Hide resolved
}

private static void ModifyImportSettingsOfRoslynAnalyzer([NotNull] PluginImporter plugin, string[] relativeRepositoryPathComponents, bool reimport)
popara96 marked this conversation as resolved.
Show resolved Hide resolved
{
plugin.SetCompatibleWithAnyPlatform(false);
plugin.SetCompatibleWithEditor(false);
Expand All @@ -191,6 +221,44 @@ private static void ModifyImportSettingsOfRoslynAnalyzer([NotNull] PluginImporte

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

// 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 assetRoslynVersion = GetRoslynVersionNumberFromAnalyzerPath(plugin.assetPath);
if (assetRoslynVersion != null)
{
var versionPrefixIndex = plugin.assetPath.IndexOf(AnalyzersRoslynVersionsFolderName, StringComparison.Ordinal);
var analyzersVersionsRoot = JoinPathComponents(plugin.assetPath.Substring(0, versionPrefixIndex), AnalyzersRoslynVersionsFolderName);
var analyzersFolders = AssetDatabase.GetSubFolders(analyzersVersionsRoot);
JoC0de marked this conversation as resolved.
Show resolved Hide resolved

var enabledRoslynVersions = analyzersFolders
.Select(GetRoslynVersionNumberFromAnalyzerPath)
.Where(ver =>
popara96 marked this conversation as resolved.
Show resolved Hide resolved
{
if (ver == null)
{
return false;
}
#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
return string.CompareOrdinal(ver, "4.3.0") <= 0;
#elif UNITY_2022_2_OR_NEWER
return string.CompareOrdinal(ver, "4.1.0") <= 0;
#elif UNITY_2021_2_OR_NEWER
return string.CompareOrdinal(ver, "3.8.0") <= 0;
#else
return false;
#endif
})
.ToArray();

// If most recent valid analyzers exist elsewhere, remove label `RoslynAnalyzer`
if (!enabledRoslynVersions.Contains(assetRoslynVersion) ||
string.CompareOrdinal(assetRoslynVersion, enabledRoslynVersions.Max()) < 0)
{
AssetDatabase.SetLabels(plugin, new[] { ProcessedLabel });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of setting and then removing the label, just save in some bool variable if RoslynAnalyzer label should be added and then in the end just SetLabels once to proper value depending on that bool.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I fixed.

}
}


if (reimport)
{
// Persist and reload the change to the meta file
Expand Down
Loading