Skip to content

allow editor only pre-imported libraries + remove language folders from NuGet lib-folder #503

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/NuGetForUnity.Tests/Assets/Tests/Editor/NuGetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

public class NuGetTests
{
[TearDown]
public void Cleanup()
{
NugetHelper.UninstallAll();
}

[Test]
public void SimpleRestoreTest()
{
Expand Down Expand Up @@ -192,6 +198,36 @@ public void InstallSignalRClientTest()
Assert.IsFalse(NugetHelper.IsInstalled(signalRClient), "The package is STILL installed: {0} {1}", signalRClient.Id, signalRClient.Version);
}

[Test]
public void InstallMicrosoftMlProbabilisticCompilerTest()
{
var probabilisticCompiler = new NugetPackageIdentifier("Microsoft.ML.Probabilistic.Compiler", "0.4.2301.301");

NugetHelper.InstallIdentifier(probabilisticCompiler);
Assert.IsTrue(
NugetHelper.IsInstalled(probabilisticCompiler),
"The package was NOT installed: {0} {1}",
probabilisticCompiler.Id,
probabilisticCompiler.Version);

var libraryDirectory = Path.Combine(
NugetHelper.NugetConfigFile.RepositoryPath,
$"{probabilisticCompiler.Id}.{probabilisticCompiler.Version}",
"lib",
"netstandard2.0");

Assert.That(libraryDirectory, Does.Exist);
Assert.That(Path.Combine(libraryDirectory, "cs"), Does.Not.Exist);

// cleanup and uninstall everything
NugetHelper.UninstallAll();
Assert.IsFalse(
NugetHelper.IsInstalled(probabilisticCompiler),
"The package is STILL installed: {0} {1}",
probabilisticCompiler.Id,
probabilisticCompiler.Version);
}

[Test]
[TestCase("1.0.0-rc1", "1.0.0")]
[TestCase("1.0.0-rc1", "1.0.0-rc2")]
Expand Down
16 changes: 16 additions & 0 deletions src/NuGetForUnity/Editor/NugetHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,22 @@ private static void CleanInstallationDirectory(NugetPackageIdentifier package)
DeleteDirectory(directory.FullName);
}
}

if (bestLibDirectory != null)
{
// some older packages e.g. Microsoft.CodeAnalysis.Common 2.10.0 have multiple localization resource files
// e.g. Microsoft.CodeAnalysis.resources.dll each inside a folder with the language name as a folder name e.g. zh-Hant or fr
// unity doesn't support importing multiple assemblies with the same file name.
// for now we just delete all folders so the language neutral version is used and Unity is happy.
var languageSupFolders = bestLibDirectory.GetDirectories();
if (languageSupFolders.All(languageSupFolder => languageSupFolder.Name.Split('-').FirstOrDefault()?.Length == 2))
{
foreach (var languageSupFolder in languageSupFolders)
{
languageSupFolder.Delete(true);
}
}
}
}
}

Expand Down
46 changes: 45 additions & 1 deletion src/NuGetForUnity/Editor/NugetPackageAssetPostprocessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class NugetPackageAssetPostprocessor : AssetPostprocessor
/// so we can change the import settings before unity throws errors about incompatibility etc..
/// Currently we change the import settings of:
/// Roslyn-Analyzers: are marked so unity knows that the *.dll's are analyzers and treats them accordingly.
/// NuGetForUnity config files: so they are not exported to WSA
/// PlayerOnly assemblies: configure the assemblies to be excluded form edit-mode
/// </summary>
private void OnPreprocessAsset()
{
Expand Down Expand Up @@ -72,14 +74,22 @@ private static (string AssetType, string AssetPath, ResultStatus Status)? Handle

var assetPathRelativeToRepository = absoluteAssetPath.Substring(absoluteRepositoryPath.Length);

// the first component is the package name
// the first component is the package name with version number
var assetPathComponents = GetPathComponents(assetPathRelativeToRepository);
if (assetPathComponents.Length > 1 && assetPathComponents[1].Equals(AnalyzersFolderName, StringComparison.OrdinalIgnoreCase))
{
var result = ModifyImportSettingsOfRoslynAnalyzer(projectRelativeAssetPath, reimport);
return ("RoslynAnalyzer", projectRelativeAssetPath, result);
}

if (assetPathComponents.Length > 0 &&
UnityPreImportedLibraryResolver.GetAlreadyImportedEditorOnlyLibraries()
.Contains(Path.GetFileNameWithoutExtension(assetPathComponents[assetPathComponents.Length - 1])))
{
var result = ModifyImportSettingsOfPlayerOnly(projectRelativeAssetPath, reimport);
return ("PlayerOnly", projectRelativeAssetPath, result);
}

return null;
}

Expand Down Expand Up @@ -140,6 +150,40 @@ private static ResultStatus ModifyImportSettingsOfRoslynAnalyzer(string analyzer
return ResultStatus.Success;
}

/// <summary>
/// Changes the importer settings to exclude it from editor.
/// This is needed for assemblies that are imported by unity but only in edit-mode so we can only import it in play-mode.
/// <seealso cref="UnityPreImportedLibraryResolver.GetAlreadyImportedEditorOnlyLibraries" />.
/// </summary>
/// <param name="assemblyAssetPath">The path to the .dll file.</param>
/// <param name="reimport">Whether or not to save and re-import the file.</param>
private static ResultStatus ModifyImportSettingsOfPlayerOnly(string assemblyAssetPath, bool reimport)
{
if (!GetPluginImporter(assemblyAssetPath, out var plugin))
{
return ResultStatus.Failure;
}

if (AlreadyProcessed(plugin))
{
return ResultStatus.AlreadyProcessed;
}

plugin.SetCompatibleWithAnyPlatform(true);
plugin.SetExcludeEditorFromAnyPlatform(true);

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

if (reimport)
{
// Persist and reload the change to the meta file
plugin.SaveAndReimport();
}

NugetHelper.LogVerbose("Configured asset '{0}' as a Player Only.", assemblyAssetPath);
return ResultStatus.Success;
}

/// <summary>
/// Changes the importer settings to disables the export to WSA Platform setting.
/// </summary>
Expand Down
37 changes: 32 additions & 5 deletions src/NuGetForUnity/Editor/UnityPreImportedLibraryResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ internal static class UnityPreImportedLibraryResolver
{
private static HashSet<string> alreadyImportedLibs;

private static HashSet<string> alreadyImportedEditorOnlyLibraries;

/// <summary>
/// Gets all libraries that are already imported by unity so we shouldn't / don't need to install them as NuGet packages.
/// </summary>
Expand All @@ -34,18 +36,15 @@ internal static HashSet<string> GetAlreadyImportedLibs()
.Select(Path.GetFileNameWithoutExtension));
}

// Search the all project assemblies that are not from a package or a Unity assembly.
// Search the all project assemblies that are not editor only.
// We only use player assemblies as we don't need to collect UnityEditor assemblies, we don't support installing NuGet packages with reference to UnityEditor.
#if UNITY_2019_3_OR_NEWER
const AssembliesType assemblieType = AssembliesType.PlayerWithoutTestAssemblies;
#else
const AssembliesType assemblieType = AssembliesType.Player;
#endif
var projectAssemblies = CompilationPipeline.GetAssemblies(assemblieType)
.Where(
playerAssembly => playerAssembly.sourceFiles.Length == 0 ||
playerAssembly.sourceFiles.Any(
sourceFilePath => sourceFilePath.StartsWith("Assets/") || sourceFilePath.StartsWith("Assets\\")));
.Where(playerAssembly => playerAssembly.flags != AssemblyFlags.EditorAssembly);

// Collect all referenced assemblies but exclude all assemblies installed by NuGetForUnity.
var porojectReferences = projectAssemblies.SelectMany(playerAssembly => playerAssembly.allReferences);
Expand All @@ -63,9 +62,37 @@ internal static HashSet<string> GetAlreadyImportedLibs()
// the compiler / language is available by default
alreadyImportedLibs.Add("Microsoft.CSharp");

var editorOnlyAssemblies = CompilationPipeline.GetAssemblies(AssembliesType.Editor)
.Where(assembly => assembly.flags == AssemblyFlags.EditorAssembly)
.ToList();
var editorReferences = editorOnlyAssemblies.SelectMany(editorOnlyAssembly => editorOnlyAssembly.allReferences);
alreadyImportedEditorOnlyLibraries = new HashSet<string>(
editorReferences.Select(Path.GetFileNameWithoutExtension).Where(assemblyName => !alreadyImportedLibs.Contains(assemblyName)));

// com.unity.visualscripting uses .net 4.8 so it implicitly has System.CodeDom
if (!alreadyImportedLibs.Contains("System.CodeDom") &&
editorOnlyAssemblies.Any(editorOnlyAssembly => editorOnlyAssembly.name == "Unity.VisualScripting.Shared.Editor"))
{
alreadyImportedEditorOnlyLibraries.Add("System.CodeDom");
}

NugetHelper.LogVerbose("Already imported libs: {0}", string.Join(", ", alreadyImportedLibs));
NugetHelper.LogVerbose("Already imported editor only libraries: {0}", string.Join(", ", alreadyImportedEditorOnlyLibraries));

return alreadyImportedLibs;
}

/// <summary>
/// </summary>
/// <returns></returns>
internal static HashSet<string> GetAlreadyImportedEditorOnlyLibraries()
{
if (alreadyImportedEditorOnlyLibraries == null)
{
GetAlreadyImportedLibs();
}

return alreadyImportedEditorOnlyLibraries;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,17 @@ PlayerSettings:
useHDRDisplay: 0
D3DHDRBitDepth: 0
m_ColorGamuts: 00000000
targetPixelDensity: 0
targetPixelDensity: 30
resolutionScalingMode: 0
resetResolutionOnWindowResize: 0
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.1
applicationIdentifier: {}
buildNumber: {}
applicationIdentifier:
Standalone: com.DefaultCompany.ImportAndUseNuGetPackages
buildNumber:
Standalone: 0
iPhone: 0
tvOS: 0
overrideDefaultApplicationIdentifier: 0
AndroidBundleVersionCode: 1
AndroidMinSdkVersion: 22
Expand All @@ -172,10 +176,10 @@ PlayerSettings:
strictShaderVariantMatching: 0
VertexChannelCompressionMask: 4054
iPhoneSdkVersion: 988
iOSTargetOSVersionString:
iOSTargetOSVersionString: 12.0
tvOSSdkVersion: 0
tvOSRequireExtendedGameController: 0
tvOSTargetOSVersionString:
tvOSTargetOSVersionString: 12.0
uIPrerenderedIcon: 0
uIRequiresPersistentWiFi: 0
uIRequiresFullScreen: 1
Expand Down Expand Up @@ -298,7 +302,7 @@ PlayerSettings:
locationUsageDescription:
microphoneUsageDescription:
bluetoothUsageDescription:
macOSTargetOSVersion:
macOSTargetOSVersion: 10.13.0
switchNMETAOverride:
switchNetLibKey:
switchSocketMemoryPoolSize: 6144
Expand Down