From 08ab0fbd80e02be20985d6c16f7e4c5ec46b2c96 Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity> Date: Fri, 30 Oct 2020 00:00:00 +0000 Subject: [PATCH] com.unity.ide.visualstudio@2.0.5 ## [2.0.5] - 2020-10-30 Integration: Disable legacy pdb symbol checking for Unity packages --- CHANGELOG.md | 7 + Editor/AssemblyInfo.cs | 4 + Editor/AssemblyInfo.cs.meta | 3 + Editor/Discovery.cs | 15 +- Editor/FileUtility.cs | 8 + Editor/Image.cs | 65 +- .../Contents.meta | 2 +- .../Contents/Info.plist | 20 +- .../Contents/Info.plist.meta | 2 +- .../Contents/MacOS.meta | 2 +- .../Contents/MacOS/AppleEventIntegration | Bin 19980 -> 55040 bytes .../Contents/MacOS/AppleEventIntegration.meta | 2 +- .../Contents/_CodeSignature.meta | 8 + .../Contents/_CodeSignature/CodeResources | 115 ++ .../_CodeSignature/CodeResources.meta | 7 + .../ProjectGeneration/AssemblyNameProvider.cs | 327 ++- Editor/ProjectGeneration/FileIOProvider.cs | 49 +- Editor/ProjectGeneration/GUIDProvider.cs | 39 +- Editor/ProjectGeneration/ProjectGeneration.cs | 1809 +++++++++-------- .../ProjectGenerationFlag.cs | 11 +- Editor/SolutionParser.cs | 1 - Editor/VisualStudioEditor.cs | 116 +- Editor/VisualStudioInstallation.cs | 11 +- Editor/VisualStudioIntegration.cs | 7 +- package.json | 8 +- 25 files changed, 1481 insertions(+), 1157 deletions(-) create mode 100644 Editor/AssemblyInfo.cs create mode 100644 Editor/AssemblyInfo.cs.meta create mode 100644 Editor/Plugins/AppleEventIntegration.bundle/Contents/_CodeSignature.meta create mode 100644 Editor/Plugins/AppleEventIntegration.bundle/Contents/_CodeSignature/CodeResources create mode 100644 Editor/Plugins/AppleEventIntegration.bundle/Contents/_CodeSignature/CodeResources.meta diff --git a/CHANGELOG.md b/CHANGELOG.md index 673f4e3..bace3ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Code Editor Package for Visual Studio +## [2.0.5] - 2020-10-30 + +Integration: + +Disable legacy pdb symbol checking for Unity packages + + ## [2.0.3] - 2020-09-09 Project generation: diff --git a/Editor/AssemblyInfo.cs b/Editor/AssemblyInfo.cs new file mode 100644 index 0000000..88f6069 --- /dev/null +++ b/Editor/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly:InternalsVisibleTo("Unity.VisualStudio.EditorTests")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/Editor/AssemblyInfo.cs.meta b/Editor/AssemblyInfo.cs.meta new file mode 100644 index 0000000..5262a54 --- /dev/null +++ b/Editor/AssemblyInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d791d407901442e49862d3aa783ce8af +timeCreated: 1602756877 \ No newline at end of file diff --git a/Editor/Discovery.cs b/Editor/Discovery.cs index 6ef89b9..893ed3a 100644 --- a/Editor/Discovery.cs +++ b/Editor/Discovery.cs @@ -15,7 +15,10 @@ namespace Microsoft.Unity.VisualStudio.Editor { internal static class Discovery { - public static IEnumerable GetVisualStudioInstallations() + internal const string ManagedWorkload = "Microsoft.VisualStudio.Workload.ManagedGame"; + + + public static IEnumerable GetVisualStudioInstallations() { if (VisualStudioEditor.IsWindows) { @@ -45,7 +48,7 @@ private static bool IsCandidateToDiscovery(string path) return false; } - public static bool TryDiscoverInstallation(string editorPath, out VisualStudioInstallation installation) + public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation) { installation = null; @@ -61,7 +64,7 @@ public static bool TryDiscoverInstallation(string editorPath, out VisualStudioIn // On Mac we use the .app folder, so we need to access to main assembly if (VisualStudioEditor.IsOSX) fvi = Path.Combine(editorPath, "Contents", "Resources", "lib", "monodevelop", "bin", "VisualStudio.exe"); - + if (!File.Exists(fvi)) return false; @@ -82,7 +85,7 @@ public static bool TryDiscoverInstallation(string editorPath, out VisualStudioIn } #region VsWhere Json Schema - #pragma warning disable CS0649 +#pragma warning disable CS0649 [Serializable] internal class VsWhereResult { @@ -95,7 +98,7 @@ public static VsWhereResult FromJson(string json) public IEnumerable ToVisualStudioInstallations() { - foreach(var entry in entries) + foreach (var entry in entries) { yield return new VisualStudioInstallation() { @@ -123,7 +126,7 @@ internal class VsWhereCatalog public string productDisplayVersion; // non parseable like "16.3.0 Preview 3.0" public string buildVersion; } - #pragma warning restore CS3021 +#pragma warning restore CS3021 #endregion private static IEnumerable QueryVsWhere() diff --git a/Editor/FileUtility.cs b/Editor/FileUtility.cs index 3e98060..3e0817f 100644 --- a/Editor/FileUtility.cs +++ b/Editor/FileUtility.cs @@ -49,6 +49,14 @@ public static string Normalize(string path) return path.Replace(string.Concat(WinSeparator, WinSeparator), WinSeparator.ToString()); } + public static string NormalizeWindowsToUnix(string path) + { + if (string.IsNullOrEmpty(path)) + return path; + + return path.Replace(WinSeparator, UnixSeparator); + } + internal static bool IsFileInProjectDirectory(string fileName) { var basePath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); diff --git a/Editor/Image.cs b/Editor/Image.cs index ca473df..b2b4fd3 100644 --- a/Editor/Image.cs +++ b/Editor/Image.cs @@ -7,28 +7,29 @@ namespace Microsoft.Unity.VisualStudio.Editor { - public sealed class Image : IDisposable { + public sealed class Image : IDisposable + { long position; Stream stream; - Image (Stream stream) + Image(Stream stream) { this.stream = stream; this.position = stream.Position; this.stream.Position = 0; } - bool Advance (int length) + bool Advance(int length) { if (stream.Position + length >= stream.Length) return false; - stream.Seek (length, SeekOrigin.Current); + stream.Seek(length, SeekOrigin.Current); return true; } - bool MoveTo (uint position) + bool MoveTo(uint position) { if (position >= stream.Length) return false; @@ -37,65 +38,65 @@ bool MoveTo (uint position) return true; } - void IDisposable.Dispose () + void IDisposable.Dispose() { stream.Position = position; } - ushort ReadUInt16 () + ushort ReadUInt16() { - return (ushort) (stream.ReadByte () - | (stream.ReadByte () << 8)); + return (ushort)(stream.ReadByte() + | (stream.ReadByte() << 8)); } - uint ReadUInt32 () + uint ReadUInt32() { - return (uint) (stream.ReadByte () - | (stream.ReadByte () << 8) - | (stream.ReadByte () << 16) - | (stream.ReadByte () << 24)); + return (uint)(stream.ReadByte() + | (stream.ReadByte() << 8) + | (stream.ReadByte() << 16) + | (stream.ReadByte() << 24)); } - bool IsManagedAssembly () + bool IsManagedAssembly() { if (stream.Length < 318) return false; - if (ReadUInt16 () != 0x5a4d) + if (ReadUInt16() != 0x5a4d) return false; - if (!Advance (58)) + if (!Advance(58)) return false; - if (!MoveTo (ReadUInt32 ())) + if (!MoveTo(ReadUInt32())) return false; - if (ReadUInt32 () != 0x00004550) + if (ReadUInt32() != 0x00004550) return false; - if (!Advance (20)) + if (!Advance(20)) return false; - if (!Advance (ReadUInt16 () == 0x20b ? 222 : 206)) + if (!Advance(ReadUInt16() == 0x20b ? 222 : 206)) return false; - return ReadUInt32 () != 0; + return ReadUInt32() != 0; } - public static bool IsAssembly (string file) + public static bool IsAssembly(string file) { if (file == null) - throw new ArgumentNullException ("file"); + throw new ArgumentNullException("file"); - using (var stream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read)) - return IsAssembly (stream); + using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)) + return IsAssembly(stream); } - public static bool IsAssembly (Stream stream) + public static bool IsAssembly(Stream stream) { if (stream == null) - throw new ArgumentNullException (nameof(stream)); + throw new ArgumentNullException(nameof(stream)); if (!stream.CanRead) - throw new ArgumentException (nameof(stream)); + throw new ArgumentException(nameof(stream)); if (!stream.CanSeek) - throw new ArgumentException (nameof(stream)); + throw new ArgumentException(nameof(stream)); - using (var image = new Image (stream)) - return image.IsManagedAssembly (); + using (var image = new Image(stream)) + return image.IsManagedAssembly(); } } } diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents.meta b/Editor/Plugins/AppleEventIntegration.bundle/Contents.meta index 03a3bfb..4ecd726 100644 --- a/Editor/Plugins/AppleEventIntegration.bundle/Contents.meta +++ b/Editor/Plugins/AppleEventIntegration.bundle/Contents.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 058b02c03ea09473aab4dc5fc50af1ef +guid: 543eb5eeeb1d5424ca8876b93fad5326 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist b/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist index 3b52961..9d34eaf 100644 --- a/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist +++ b/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist @@ -3,7 +3,7 @@ BuildMachineOSBuild - 19B88 + 19H2 CFBundleDevelopmentRegion en CFBundleExecutable @@ -14,6 +14,8 @@ 6.0 CFBundleName AppleEventIntegration + CFBundlePackageType + BNDL CFBundleShortVersionString 1.0 CFBundleSupportedPlatforms @@ -25,17 +27,21 @@ DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild - 10E125 + 12A7300 + DTPlatformName + macosx DTPlatformVersion - GM + 10.15.6 DTSDKBuild - 18E219 + 19G68 DTSDKName - macosx10.14 + macosx10.15 DTXcode - 1020 + 1201 DTXcodeBuild - 10E125 + 12A7300 + LSMinimumSystemVersion + 10.13 NSHumanReadableCopyright Copyright © 2019 Unity. All rights reserved. diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist.meta b/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist.meta index 1f49dac..2f42690 100644 --- a/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist.meta +++ b/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 680cf1008b4284eddbb82ec4d76644a1 +guid: 29239d79a3471495e9d270601006dad7 DefaultImporter: externalObjects: {} userData: diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS.meta b/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS.meta index 8c69d7f..c99cb41 100644 --- a/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS.meta +++ b/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: ba4355216f6c44abbb17503872c42c97 +guid: e811c7e1c1e9a4b50b237772d317959f folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS/AppleEventIntegration b/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS/AppleEventIntegration index bf56250f6f8076a7d47f208584335ee5dd76ee92..2b35f07b31468458eee5d89d32c97737eb05cf82 100644 GIT binary patch literal 55040 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 + + + + files + + files2 + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents/_CodeSignature/CodeResources.meta b/Editor/Plugins/AppleEventIntegration.bundle/Contents/_CodeSignature/CodeResources.meta new file mode 100644 index 0000000..14bac5b --- /dev/null +++ b/Editor/Plugins/AppleEventIntegration.bundle/Contents/_CodeSignature/CodeResources.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3379e8bd711774041a330f218af69b7a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ProjectGeneration/AssemblyNameProvider.cs b/Editor/ProjectGeneration/AssemblyNameProvider.cs index ebe3f6d..90787ad 100644 --- a/Editor/ProjectGeneration/AssemblyNameProvider.cs +++ b/Editor/ProjectGeneration/AssemblyNameProvider.cs @@ -1,3 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Unity Technologies. + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ using System; using System.Collections.Generic; using System.Linq; @@ -7,181 +12,175 @@ namespace Microsoft.Unity.VisualStudio.Editor { - public interface IAssemblyNameProvider - { - string[] ProjectSupportedExtensions { get; } - string ProjectGenerationRootNamespace { get; } - ProjectGenerationFlag ProjectGenerationFlag { get; } + public interface IAssemblyNameProvider + { + string[] ProjectSupportedExtensions { get; } + string ProjectGenerationRootNamespace { get; } + ProjectGenerationFlag ProjectGenerationFlag { get; } - string GetAssemblyNameFromScriptPath(string path); + string GetAssemblyNameFromScriptPath(string path); string GetAssemblyName(string assemblyOutputPath, string assemblyName); bool IsInternalizedPackagePath(string path); - IEnumerable GetAssemblies(Func shouldFileBePartOfSolution); - IEnumerable GetAllAssetPaths(); - UnityEditor.PackageManager.PackageInfo FindForAssetPath(string assetPath); - ResponseFileData ParseResponseFile(string responseFilePath, string projectDirectory, string[] systemReferenceDirectories); - void ToggleProjectGeneration(ProjectGenerationFlag preference); - } - - public class AssemblyNameProvider : IAssemblyNameProvider - { - ProjectGenerationFlag m_ProjectGenerationFlag = (ProjectGenerationFlag)EditorPrefs.GetInt( - "unity_project_generation_flag", - (int)(ProjectGenerationFlag.Local | ProjectGenerationFlag.Embedded)); - - public string[] ProjectSupportedExtensions => EditorSettings.projectGenerationUserExtensions; - - public string ProjectGenerationRootNamespace => EditorSettings.projectGenerationRootNamespace; - - public ProjectGenerationFlag ProjectGenerationFlag - { - get => m_ProjectGenerationFlag; - private set - { - EditorPrefs.SetInt("unity_project_generation_flag", (int)value); - m_ProjectGenerationFlag = value; - } - } - - public string GetAssemblyNameFromScriptPath(string path) - { - return CompilationPipeline.GetAssemblyNameFromScriptPath(path); - } - - public IEnumerable GetAssemblies(Func shouldFileBePartOfSolution) - { - foreach (var assembly in CompilationPipeline.GetAssemblies()) - { - if (assembly.sourceFiles.Any(shouldFileBePartOfSolution)) - { - var options = new ScriptCompilerOptions() - { - ResponseFiles = assembly.compilerOptions.ResponseFiles, - AllowUnsafeCode = assembly.compilerOptions.AllowUnsafeCode, - ApiCompatibilityLevel = assembly.compilerOptions.ApiCompatibilityLevel - }; - - yield return new Assembly(assembly.name, @"Temp\Bin\Debug\", - assembly.sourceFiles, new[] { "DEBUG", "TRACE" }.Concat(assembly.defines).Concat(EditorUserBuildSettings.activeScriptCompilationDefines).ToArray(), - assembly.assemblyReferences, - assembly.compiledAssemblyReferences, - assembly.flags, + IEnumerable GetAssemblies(Func shouldFileBePartOfSolution); + IEnumerable GetAllAssetPaths(); + UnityEditor.PackageManager.PackageInfo FindForAssetPath(string assetPath); + ResponseFileData ParseResponseFile(string responseFilePath, string projectDirectory, string[] systemReferenceDirectories); + void ToggleProjectGeneration(ProjectGenerationFlag preference); + } + + public class AssemblyNameProvider : IAssemblyNameProvider + { + ProjectGenerationFlag m_ProjectGenerationFlag = (ProjectGenerationFlag)EditorPrefs.GetInt( + "unity_project_generation_flag", + (int)(ProjectGenerationFlag.Local | ProjectGenerationFlag.Embedded)); + + public string[] ProjectSupportedExtensions => EditorSettings.projectGenerationUserExtensions; + + public string ProjectGenerationRootNamespace => EditorSettings.projectGenerationRootNamespace; + + public ProjectGenerationFlag ProjectGenerationFlag + { + get => m_ProjectGenerationFlag; + private set + { + EditorPrefs.SetInt("unity_project_generation_flag", (int)value); + m_ProjectGenerationFlag = value; + } + } + + public string GetAssemblyNameFromScriptPath(string path) + { + return CompilationPipeline.GetAssemblyNameFromScriptPath(path); + } + + public IEnumerable GetAssemblies(Func shouldFileBePartOfSolution) + { + foreach (var assembly in CompilationPipeline.GetAssemblies()) + { + if (assembly.sourceFiles.Any(shouldFileBePartOfSolution)) + { + var options = new ScriptCompilerOptions + { + ResponseFiles = assembly.compilerOptions.ResponseFiles, + AllowUnsafeCode = assembly.compilerOptions.AllowUnsafeCode, + ApiCompatibilityLevel = assembly.compilerOptions.ApiCompatibilityLevel + }; + + yield return new Assembly(assembly.name, @"Temp\Bin\Debug\", + assembly.sourceFiles, new[] { "DEBUG", "TRACE" }.Concat(assembly.defines).Concat(EditorUserBuildSettings.activeScriptCompilationDefines).ToArray(), + assembly.assemblyReferences, + assembly.compiledAssemblyReferences, + assembly.flags, #if UNITY_2020_2_OR_NEWER options, assembly.rootNamespace); #else - options); + options); #endif - } - } - - if (ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.PlayerAssemblies)) - { - foreach (var assembly in CompilationPipeline.GetAssemblies(AssembliesType.Player).Where(assembly => assembly.sourceFiles.Any(shouldFileBePartOfSolution))) - { - var options = new ScriptCompilerOptions() - { - ResponseFiles = assembly.compilerOptions.ResponseFiles, - AllowUnsafeCode = assembly.compilerOptions.AllowUnsafeCode, - ApiCompatibilityLevel = assembly.compilerOptions.ApiCompatibilityLevel - }; - - yield return new Assembly(assembly.name, @"Temp\Bin\Debug\Player\", - assembly.sourceFiles, - new[] { "DEBUG", "TRACE" }.Concat(assembly.defines).ToArray(), - assembly.assemblyReferences, - assembly.compiledAssemblyReferences, - assembly.flags, + } + } + + if (ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.PlayerAssemblies)) + { + foreach (var assembly in CompilationPipeline.GetAssemblies(AssembliesType.Player).Where(assembly => assembly.sourceFiles.Any(shouldFileBePartOfSolution))) + { + var options = new ScriptCompilerOptions + { + ResponseFiles = assembly.compilerOptions.ResponseFiles, + AllowUnsafeCode = assembly.compilerOptions.AllowUnsafeCode, + ApiCompatibilityLevel = assembly.compilerOptions.ApiCompatibilityLevel + }; + + yield return + new Assembly(assembly.name, @"Temp\Bin\Debug\Player\", + assembly.sourceFiles, + new[] { "DEBUG", "TRACE" }.Concat(assembly.defines).ToArray(), + assembly.assemblyReferences, + assembly.compiledAssemblyReferences, + assembly.flags, #if UNITY_2020_2_OR_NEWER - options, - assembly.rootNamespace); + options, + assembly.rootNamespace); #else - options); + options); #endif - } - } - } - - public string GetCompileOutputPath(string assemblyName) - { - if (assemblyName.EndsWith(".Player", StringComparison.Ordinal)) - { - return @"Temp\Bin\Debug\Player\"; - } - else - { - return @"Temp\Bin\Debug\"; - } - } - - public IEnumerable GetAllAssetPaths() - { - return AssetDatabase.GetAllAssetPaths(); - } - - public UnityEditor.PackageManager.PackageInfo FindForAssetPath(string assetPath) - { - return UnityEditor.PackageManager.PackageInfo.FindForAssetPath(assetPath); - } - - public bool IsInternalizedPackagePath(string path) - { - if (string.IsNullOrEmpty(path.Trim())) - { - return false; - } - var packageInfo = FindForAssetPath(path); - if (packageInfo == null) - { - return false; - } - var packageSource = packageInfo.source; - switch (packageSource) - { - case PackageSource.Embedded: - return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Embedded); - case PackageSource.Registry: - return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Registry); - case PackageSource.BuiltIn: - return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.BuiltIn); - case PackageSource.Unknown: - return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Unknown); - case PackageSource.Local: - return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Local); - case PackageSource.Git: - return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Git); - case PackageSource.LocalTarball: - return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.LocalTarBall); - } - - return false; - } - - public ResponseFileData ParseResponseFile(string responseFilePath, string projectDirectory, string[] systemReferenceDirectories) - { - return CompilationPipeline.ParseResponseFile( - responseFilePath, - projectDirectory, - systemReferenceDirectories - ); - } - - public void ToggleProjectGeneration(ProjectGenerationFlag preference) - { - if (ProjectGenerationFlag.HasFlag(preference)) - { - ProjectGenerationFlag ^= preference; - } - else - { - ProjectGenerationFlag |= preference; - } - } - - public void ResetProjectGenerationFlag() - { - ProjectGenerationFlag = ProjectGenerationFlag.None; - } + } + } + } + + public string GetCompileOutputPath(string assemblyName) + { + return assemblyName.EndsWith(".Player", StringComparison.Ordinal) ? @"Temp\Bin\Debug\Player\" : @"Temp\Bin\Debug\"; + } + + public IEnumerable GetAllAssetPaths() + { + return AssetDatabase.GetAllAssetPaths(); + } + + public UnityEditor.PackageManager.PackageInfo FindForAssetPath(string assetPath) + { + return UnityEditor.PackageManager.PackageInfo.FindForAssetPath(assetPath); + } + + public bool IsInternalizedPackagePath(string path) + { + if (string.IsNullOrEmpty(path.Trim())) + { + return false; + } + var packageInfo = FindForAssetPath(path); + if (packageInfo == null) + { + return false; + } + var packageSource = packageInfo.source; + switch (packageSource) + { + case PackageSource.Embedded: + return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Embedded); + case PackageSource.Registry: + return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Registry); + case PackageSource.BuiltIn: + return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.BuiltIn); + case PackageSource.Unknown: + return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Unknown); + case PackageSource.Local: + return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Local); + case PackageSource.Git: + return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.Git); + case PackageSource.LocalTarball: + return !ProjectGenerationFlag.HasFlag(ProjectGenerationFlag.LocalTarBall); + } + + return false; + } + + public ResponseFileData ParseResponseFile(string responseFilePath, string projectDirectory, string[] systemReferenceDirectories) + { + return CompilationPipeline.ParseResponseFile( + responseFilePath, + projectDirectory, + systemReferenceDirectories + ); + } + + public void ToggleProjectGeneration(ProjectGenerationFlag preference) + { + if (ProjectGenerationFlag.HasFlag(preference)) + { + ProjectGenerationFlag ^= preference; + } + else + { + ProjectGenerationFlag |= preference; + } + } + + public void ResetProjectGenerationFlag() + { + ProjectGenerationFlag = ProjectGenerationFlag.None; + } public string GetAssemblyName(string assemblyOutputPath, string assemblyName) { diff --git a/Editor/ProjectGeneration/FileIOProvider.cs b/Editor/ProjectGeneration/FileIOProvider.cs index c22548c..16421b1 100644 --- a/Editor/ProjectGeneration/FileIOProvider.cs +++ b/Editor/ProjectGeneration/FileIOProvider.cs @@ -1,31 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Unity Technologies. + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ using System.IO; using System.Text; namespace Microsoft.Unity.VisualStudio.Editor { - public interface IFileIO - { - bool Exists(string fileName); + public interface IFileIO + { + bool Exists(string fileName); - string ReadAllText(string fileName); - void WriteAllText(string fileName, string content); - } + string ReadAllText(string fileName); + void WriteAllText(string fileName, string content); + } - class FileIOProvider : IFileIO - { - public bool Exists(string fileName) - { - return File.Exists(fileName); - } + class FileIOProvider : IFileIO + { + public bool Exists(string fileName) + { + return File.Exists(fileName); + } - public string ReadAllText(string fileName) - { - return File.ReadAllText(fileName); - } + public string ReadAllText(string fileName) + { + return File.ReadAllText(fileName); + } - public void WriteAllText(string fileName, string content) - { - File.WriteAllText(fileName, content, Encoding.UTF8); - } - } -} \ No newline at end of file + public void WriteAllText(string fileName, string content) + { + File.WriteAllText(fileName, content, Encoding.UTF8); + } + } +} diff --git a/Editor/ProjectGeneration/GUIDProvider.cs b/Editor/ProjectGeneration/GUIDProvider.cs index 3b1d16e..829cd4e 100644 --- a/Editor/ProjectGeneration/GUIDProvider.cs +++ b/Editor/ProjectGeneration/GUIDProvider.cs @@ -1,21 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Unity Technologies. + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ namespace Microsoft.Unity.VisualStudio.Editor { - public interface IGUIDGenerator - { - string ProjectGuid(string projectName, string assemblyName); - string SolutionGuid(string projectName, ScriptingLanguage scriptingLanguage); - } + public interface IGUIDGenerator + { + string ProjectGuid(string projectName, string assemblyName); + string SolutionGuid(string projectName, ScriptingLanguage scriptingLanguage); + } - class GUIDProvider : IGUIDGenerator - { - public string ProjectGuid(string projectName, string assemblyName) - { - return SolutionGuidGenerator.GuidForProject(projectName + assemblyName); - } + class GUIDProvider : IGUIDGenerator + { + public string ProjectGuid(string projectName, string assemblyName) + { + return SolutionGuidGenerator.GuidForProject(projectName + assemblyName); + } - public string SolutionGuid(string projectName, ScriptingLanguage scriptingLanguage) - { - return SolutionGuidGenerator.GuidForSolution(projectName, scriptingLanguage); - } - } -} \ No newline at end of file + public string SolutionGuid(string projectName, ScriptingLanguage scriptingLanguage) + { + return SolutionGuidGenerator.GuidForSolution(projectName, scriptingLanguage); + } + } +} diff --git a/Editor/ProjectGeneration/ProjectGeneration.cs b/Editor/ProjectGeneration/ProjectGeneration.cs index 2f39944..f3d3a45 100644 --- a/Editor/ProjectGeneration/ProjectGeneration.cs +++ b/Editor/ProjectGeneration/ProjectGeneration.cs @@ -15,922 +15,981 @@ using Unity.CodeEditor; using UnityEditor; using UnityEditor.Compilation; -using UnityEditor.PackageManager; using UnityEditorInternal; using UnityEngine; namespace Microsoft.Unity.VisualStudio.Editor { - public enum ScriptingLanguage - { - None, - CSharp - } - - public interface IGenerator - { - bool SyncIfNeeded(IEnumerable affectedFiles, IEnumerable reimportedFiles); - void Sync(); - bool HasSolutionBeenGenerated(); - bool IsSupportedFile(string path); - string SolutionFile(); - string ProjectDirectory { get; } - IAssemblyNameProvider AssemblyNameProvider { get; } - } - - public class ProjectGeneration : IGenerator - { - public static readonly string MSBuildNamespaceUri = "http://schemas.microsoft.com/developer/msbuild/2003"; - - const string k_WindowsNewline = "\r\n"; - - string m_SolutionProjectEntryTemplate = @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""{4}EndProject"; - - string m_SolutionProjectConfigurationTemplate = string.Join("\r\n", - @" {{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", - @" {{{0}}}.Debug|Any CPU.Build.0 = Debug|Any CPU", - @" {{{0}}}.Release|Any CPU.ActiveCfg = Release|Any CPU", - @" {{{0}}}.Release|Any CPU.Build.0 = Release|Any CPU").Replace(" ", "\t"); - - static readonly string[] k_ReimportSyncExtensions = { ".dll", ".asmdef" }; - - static readonly Regex k_ScriptReferenceExpression = new Regex( - @"^Library.ScriptAssemblies.(?(?.*)\.dll$)", - RegexOptions.Compiled | RegexOptions.IgnoreCase); - - string[] m_ProjectSupportedExtensions = new string[0]; - string[] m_BuiltinSupportedExtensions = new string[0]; - - public string ProjectDirectory { get; } - - readonly string m_ProjectName; - readonly IAssemblyNameProvider m_AssemblyNameProvider; - readonly IFileIO m_FileIOProvider; - readonly IGUIDGenerator m_GUIDGenerator; - VisualStudioInstallation m_CurrentInstallation; - public IAssemblyNameProvider AssemblyNameProvider => m_AssemblyNameProvider; - - public ProjectGeneration() : this(Directory.GetParent(Application.dataPath).FullName) - { - } - - public ProjectGeneration(string tempDirectory) : this(tempDirectory, new AssemblyNameProvider(), new FileIOProvider(), new GUIDProvider()) - { - } - - public ProjectGeneration(string tempDirectory, IAssemblyNameProvider assemblyNameProvider, IFileIO fileIoProvider, IGUIDGenerator guidGenerator) - { - ProjectDirectory = tempDirectory.Replace('\\', '/'); - m_ProjectName = Path.GetFileName(ProjectDirectory); - m_AssemblyNameProvider = assemblyNameProvider; - m_FileIOProvider = fileIoProvider; - m_GUIDGenerator = guidGenerator; - - SetupProjectSupportedExtensions(); - } - - /// - /// Syncs the scripting solution if any affected files are relevant. - /// - /// - /// Whether the solution was synced. - /// - /// - /// A set of files whose status has changed - /// - /// - /// A set of files that got reimported - /// - public bool SyncIfNeeded(IEnumerable affectedFiles, IEnumerable reimportedFiles) - { - SetupProjectSupportedExtensions(); - - // Don't sync if we haven't synced before - if (HasSolutionBeenGenerated() && HasFilesBeenModified(affectedFiles, reimportedFiles)) - { - Sync(); - return true; - } - return false; - } - - bool HasFilesBeenModified(IEnumerable affectedFiles, IEnumerable reimportedFiles) - { - return affectedFiles.Any(ShouldFileBePartOfSolution) || reimportedFiles.Any(ShouldSyncOnReimportedAsset); - } - - static bool ShouldSyncOnReimportedAsset(string asset) - { - return k_ReimportSyncExtensions.Contains(new FileInfo(asset).Extension); - } - - private void RefreshCurrentInstallation() - { - var editor = CodeEditor.CurrentEditor as VisualStudioEditor; - editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, out m_CurrentInstallation); - } - - public void Sync() - { - // We need the exact VS version/capabilities to tweak project generation (analyzers/langversion) - RefreshCurrentInstallation(); - - SetupProjectSupportedExtensions(); - var externalCodeAlreadyGeneratedProjects = OnPreGeneratingCSProjectFiles(); - - if (!externalCodeAlreadyGeneratedProjects) - { - GenerateAndWriteSolutionAndProjects(); - } - OnGeneratedCSProjectFiles(); - } - - public bool HasSolutionBeenGenerated() - { - return m_FileIOProvider.Exists(SolutionFile()); - } - - void SetupProjectSupportedExtensions() - { - m_ProjectSupportedExtensions = m_AssemblyNameProvider.ProjectSupportedExtensions; - m_BuiltinSupportedExtensions = EditorSettings.projectGenerationBuiltinExtensions; - } - - bool ShouldFileBePartOfSolution(string file) - { - // Exclude files coming from packages except if they are internalized. - if (m_AssemblyNameProvider.IsInternalizedPackagePath(file)) - { - return false; - } - - return IsSupportedFile(file); - } - - static string GetExtensionWithoutDot(string path) - { - // Prevent re-processing and information loss - if (!Path.HasExtension(path)) - return path; - - return Path - .GetExtension(path) - .TrimStart('.') - .ToLower(); - } - - public bool IsSupportedFile(string path) - { - var extension = GetExtensionWithoutDot(path); - - // Dll's are not scripts but still need to be included - if (extension == "dll") - return true; - - if (extension == "asmdef") - return true; - - if (m_BuiltinSupportedExtensions.Contains(extension)) - return true; - - if (m_ProjectSupportedExtensions.Contains(extension)) - return true; - - return false; - } - - static ScriptingLanguage ScriptingLanguageFor(Assembly assembly) - { - var files = assembly.sourceFiles; - - if (files.Length == 0) - return ScriptingLanguage.None; - - return ScriptingLanguageFor(files[0]); - } - - static ScriptingLanguage ScriptingLanguageFor(string path) - { - return GetExtensionWithoutDot(path) == "cs" ? ScriptingLanguage.CSharp : ScriptingLanguage.None; - } - - public void GenerateAndWriteSolutionAndProjects() - { - // Only synchronize assemblies that have associated source files and ones that we actually want in the project. - // This also filters out DLLs coming from .asmdef files in packages. - var assemblies = m_AssemblyNameProvider.GetAssemblies(ShouldFileBePartOfSolution); - - var allAssetProjectParts = GenerateAllAssetProjectParts(); - - var assemblyList = assemblies.ToList(); - - SyncSolution(assemblyList); - var allProjectAssemblies = RelevantAssembliesForMode(assemblyList).ToList(); - foreach (Assembly assembly in allProjectAssemblies) - { - var responseFileData = ParseResponseFileData(assembly); - SyncProject(assembly, allAssetProjectParts, responseFileData, allProjectAssemblies); - } - } - - IEnumerable ParseResponseFileData(Assembly assembly) - { - var systemReferenceDirectories = CompilationPipeline.GetSystemAssemblyDirectories(assembly.compilerOptions.ApiCompatibilityLevel); - - Dictionary responseFilesData = assembly.compilerOptions.ResponseFiles.ToDictionary(x => x, x => m_AssemblyNameProvider.ParseResponseFile( - x, - ProjectDirectory, - systemReferenceDirectories - )); - - Dictionary responseFilesWithErrors = responseFilesData.Where(x => x.Value.Errors.Any()) - .ToDictionary(x => x.Key, x => x.Value); - - if (responseFilesWithErrors.Any()) - { - foreach (var error in responseFilesWithErrors) - foreach (var valueError in error.Value.Errors) - { - Debug.LogError($"{error.Key} Parse Error : {valueError}"); - } - } + public enum ScriptingLanguage + { + None, + CSharp + } + + public interface IGenerator + { + bool SyncIfNeeded(IEnumerable affectedFiles, IEnumerable reimportedFiles); + void Sync(); + bool HasSolutionBeenGenerated(); + bool IsSupportedFile(string path); + string SolutionFile(); + string ProjectDirectory { get; } + IAssemblyNameProvider AssemblyNameProvider { get; } + } + + public class ProjectGeneration : IGenerator + { + public static readonly string MSBuildNamespaceUri = "http://schemas.microsoft.com/developer/msbuild/2003"; + public IAssemblyNameProvider AssemblyNameProvider => m_AssemblyNameProvider; + public string ProjectDirectory { get; } + + const string k_WindowsNewline = "\r\n"; + + string m_SolutionProjectEntryTemplate = @"Project(""{{{0}}}"") = ""{1}"", ""{2}"", ""{{{3}}}""{4}EndProject"; + + string m_SolutionProjectConfigurationTemplate = string.Join("\r\n", + @" {{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", + @" {{{0}}}.Debug|Any CPU.Build.0 = Debug|Any CPU", + @" {{{0}}}.Release|Any CPU.ActiveCfg = Release|Any CPU", + @" {{{0}}}.Release|Any CPU.Build.0 = Release|Any CPU").Replace(" ", "\t"); + + static readonly string[] k_ReimportSyncExtensions = { ".dll", ".asmdef" }; + + static readonly Regex k_ScriptReferenceExpression = new Regex( + @"^Library.ScriptAssemblies.(?(?.*)\.dll$)", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + string[] m_ProjectSupportedExtensions = Array.Empty(); + string[] m_BuiltinSupportedExtensions = Array.Empty(); + + readonly string m_ProjectName; + readonly IAssemblyNameProvider m_AssemblyNameProvider; + readonly IFileIO m_FileIOProvider; + readonly IGUIDGenerator m_GUIDGenerator; + bool m_ShouldGenerateAll; + IVisualStudioInstallation m_CurrentInstallation; + + public ProjectGeneration() : this(Directory.GetParent(Application.dataPath).FullName) + { + } - return responseFilesData.Select(x => x.Value); - } + public ProjectGeneration(string tempDirectory) : this(tempDirectory, new AssemblyNameProvider(), new FileIOProvider(), new GUIDProvider()) + { + } - Dictionary GenerateAllAssetProjectParts() - { - Dictionary stringBuilders = new Dictionary(); + public ProjectGeneration(string tempDirectory, IAssemblyNameProvider assemblyNameProvider, IFileIO fileIoProvider, IGUIDGenerator guidGenerator) + { + ProjectDirectory = FileUtility.NormalizeWindowsToUnix(tempDirectory); + m_ProjectName = Path.GetFileName(ProjectDirectory); + m_AssemblyNameProvider = assemblyNameProvider; + m_FileIOProvider = fileIoProvider; + m_GUIDGenerator = guidGenerator; - foreach (string asset in m_AssemblyNameProvider.GetAllAssetPaths()) - { - // Exclude files coming from packages except if they are internalized. - if (m_AssemblyNameProvider.IsInternalizedPackagePath(asset)) - { - continue; - } + SetupProjectSupportedExtensions(); + } - if (IsSupportedFile(asset) && ScriptingLanguage.None == ScriptingLanguageFor(asset)) - { - // Find assembly the asset belongs to by adding script extension and using compilation pipeline. - var assemblyName = m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".cs"); + /// + /// Syncs the scripting solution if any affected files are relevant. + /// + /// + /// Whether the solution was synced. + /// + /// + /// A set of files whose status has changed + /// + /// + /// A set of files that got reimported + /// + public bool SyncIfNeeded(IEnumerable affectedFiles, IEnumerable reimportedFiles) + { + SetupProjectSupportedExtensions(); + + // See https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/ + // We create a .vsconfig file to make sure our ManagedGame workload is installed + CreateVsConfigIfNotFound(); + + // Don't sync if we haven't synced before + if (HasSolutionBeenGenerated() && HasFilesBeenModified(affectedFiles, reimportedFiles)) + { + Sync(); + return true; + } + return false; + } - if (string.IsNullOrEmpty(assemblyName)) - { - continue; - } + private void CreateVsConfigIfNotFound() + { + try + { + var vsConfigFile = VsConfigFile(); + if (m_FileIOProvider.Exists(vsConfigFile)) + return; + + var content = $@"{{ + ""version"": ""1.0"", + ""components"": [ + ""{Discovery.ManagedWorkload}"" + ] +}} +"; + m_FileIOProvider.WriteAllText(vsConfigFile, content); + } + catch (IOException) + { + } + } - assemblyName = Path.GetFileNameWithoutExtension(assemblyName); + private bool HasFilesBeenModified(IEnumerable affectedFiles, IEnumerable reimportedFiles) + { + return affectedFiles.Any(ShouldFileBePartOfSolution) || reimportedFiles.Any(ShouldSyncOnReimportedAsset); + } - if (!stringBuilders.TryGetValue(assemblyName, out var projectBuilder)) - { - projectBuilder = new StringBuilder(); - stringBuilders[assemblyName] = projectBuilder; - } + private static bool ShouldSyncOnReimportedAsset(string asset) + { + return k_ReimportSyncExtensions.Contains(new FileInfo(asset).Extension); + } - projectBuilder.Append(" ").Append(k_WindowsNewline); - } - } - - var result = new Dictionary(); - - foreach (var entry in stringBuilders) - result[entry.Key] = entry.Value.ToString(); - - return result; - } - - void SyncProject( - Assembly assembly, - Dictionary allAssetsProjectParts, - IEnumerable responseFilesData, - List allProjectAssemblies) - { - SyncProjectFileIfNotChanged(ProjectFile(assembly), ProjectText(assembly, allAssetsProjectParts, responseFilesData, allProjectAssemblies)); - } - - void SyncProjectFileIfNotChanged(string path, string newContents) - { - if (Path.GetExtension(path) == ".csproj") - { - newContents = OnGeneratedCSProject(path, newContents); - } - - SyncFileIfNotChanged(path, newContents); - } - - void SyncSolutionFileIfNotChanged(string path, string newContents) - { - newContents = OnGeneratedSlnSolution(path, newContents); - - SyncFileIfNotChanged(path, newContents); - } - - static IEnumerable GetPostProcessorCallbacks(string name) - { - return TypeCache - .GetTypesDerivedFrom() - .Select(t => t.GetMethod(name, SR.BindingFlags.Public | SR.BindingFlags.NonPublic | SR.BindingFlags.Static)) - .Where(m => m!= null); - } - - static void OnGeneratedCSProjectFiles() - { - foreach(var method in GetPostProcessorCallbacks(nameof(OnGeneratedCSProjectFiles))) - { - method.Invoke(null, Array.Empty()); - } - } - - static bool OnPreGeneratingCSProjectFiles() - { - bool result = false; - - foreach(var method in GetPostProcessorCallbacks(nameof(OnPreGeneratingCSProjectFiles))) - { - var retValue = method.Invoke(null, Array.Empty()); - if (method.ReturnType == typeof(bool)) - { - result |= (bool)retValue; - } - } - - return result; - } - - static string InvokeAssetPostProcessorGenerationCallbacks(string name, string path, string content) - { - foreach(var method in GetPostProcessorCallbacks(name)) - { - var args = new [] { path, content }; - var returnValue = method.Invoke(null, args); - if (method.ReturnType == typeof(string)) - { - // We want to chain content update between invocations - content = (string)returnValue; - } - } - - return content; - } - - static string OnGeneratedCSProject(string path, string content) - { - return InvokeAssetPostProcessorGenerationCallbacks(nameof(OnGeneratedCSProject), path, content); - } - - static string OnGeneratedSlnSolution(string path, string content) - { - return InvokeAssetPostProcessorGenerationCallbacks(nameof(OnGeneratedSlnSolution), path, content); - } - - void SyncFileIfNotChanged(string filename, string newContents) - { - try - { - if (m_FileIOProvider.Exists(filename) && newContents == m_FileIOProvider.ReadAllText(filename)) - { - return; - } - } - catch (Exception exception) - { - Debug.LogException(exception); - } - - m_FileIOProvider.WriteAllText(filename, newContents); - } - - string ProjectText(Assembly assembly, - Dictionary allAssetsProjectParts, - IEnumerable responseFilesData, - List allProjectAsemblies) - { - var projectBuilder = new StringBuilder(ProjectHeader(assembly, responseFilesData)); - var references = new List(); - - projectBuilder.Append(@" ").Append(k_WindowsNewline); - foreach (string file in assembly.sourceFiles) - { - if (!IsSupportedFile(file)) - continue; - - var extension = Path.GetExtension(file).ToLower(); - var fullFile = EscapedRelativePathFor(file); - if (".dll" != extension) - { - projectBuilder.Append(" ").Append(k_WindowsNewline); - } - else - { - references.Add(fullFile); - } - } - projectBuilder.Append(@" ").Append(k_WindowsNewline); - - projectBuilder.Append(@" ").Append(k_WindowsNewline); - - // Append additional non-script files that should be included in project generation. - if (allAssetsProjectParts.TryGetValue(assembly.name, out var additionalAssetsForProject)) - projectBuilder.Append(additionalAssetsForProject); - - var responseRefs = responseFilesData.SelectMany(x => x.FullPathReferences.Select(r => r)); - var internalAssemblyReferences = assembly.assemblyReferences - .Where(i => !i.sourceFiles.Any(ShouldFileBePartOfSolution)).Select(i => i.outputPath); - var allReferences = - assembly.compiledAssemblyReferences - .Union(responseRefs) - .Union(references) - .Union(internalAssemblyReferences); - foreach (var reference in allReferences) - { - string fullReference = Path.IsPathRooted(reference) ? reference : Path.Combine(ProjectDirectory, reference); - AppendReference(fullReference, projectBuilder); - } - - projectBuilder.Append(@" ").Append(k_WindowsNewline); - - if (0 < assembly.assemblyReferences.Length) - { - projectBuilder.Append(" ").Append(k_WindowsNewline); - foreach (Assembly reference in assembly.assemblyReferences.Where(i => i.sourceFiles.Any(ShouldFileBePartOfSolution))) - { - projectBuilder.Append(" ").Append(k_WindowsNewline); - projectBuilder.Append(" {").Append(ProjectGuid(reference)).Append("}").Append(k_WindowsNewline); - projectBuilder.Append(" ").Append(reference.name).Append("").Append(k_WindowsNewline); - projectBuilder.Append(" ").Append(k_WindowsNewline); - } + private void RefreshCurrentInstallation() + { + var editor = CodeEditor.CurrentEditor as VisualStudioEditor; + editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, out m_CurrentInstallation); + } + + public void Sync() + { + // We need the exact VS version/capabilities to tweak project generation (analyzers/langversion) + RefreshCurrentInstallation(); + + SetupProjectSupportedExtensions(); + var externalCodeAlreadyGeneratedProjects = OnPreGeneratingCSProjectFiles(); + + if (!externalCodeAlreadyGeneratedProjects) + { + GenerateAndWriteSolutionAndProjects(); + } + OnGeneratedCSProjectFiles(); + } + + public bool HasSolutionBeenGenerated() + { + return m_FileIOProvider.Exists(SolutionFile()); + } + + private void SetupProjectSupportedExtensions() + { + m_ProjectSupportedExtensions = m_AssemblyNameProvider.ProjectSupportedExtensions; + m_BuiltinSupportedExtensions = EditorSettings.projectGenerationBuiltinExtensions; + } + + private bool ShouldFileBePartOfSolution(string file) + { + // Exclude files coming from packages except if they are internalized. + if (m_AssemblyNameProvider.IsInternalizedPackagePath(file)) + { + return false; + } + + return IsSupportedFile(file); + } + + private static string GetExtensionWithoutDot(string path) + { + // Prevent re-processing and information loss + if (!Path.HasExtension(path)) + return path; + + return Path + .GetExtension(path) + .TrimStart('.') + .ToLower(); + } + + public bool IsSupportedFile(string path) + { + var extension = GetExtensionWithoutDot(path); + + // Dll's are not scripts but still need to be included + if (extension == "dll") + return true; + + if (extension == "asmdef") + return true; + + if (m_BuiltinSupportedExtensions.Contains(extension)) + return true; + + if (m_ProjectSupportedExtensions.Contains(extension)) + return true; + + return false; + } + + private static ScriptingLanguage ScriptingLanguageFor(Assembly assembly) + { + var files = assembly.sourceFiles; + + if (files.Length == 0) + return ScriptingLanguage.None; + + return ScriptingLanguageFor(files[0]); + } + + internal static ScriptingLanguage ScriptingLanguageFor(string path) + { + return GetExtensionWithoutDot(path) == "cs" ? ScriptingLanguage.CSharp : ScriptingLanguage.None; + } + + public void GenerateAndWriteSolutionAndProjects() + { + // Only synchronize assemblies that have associated source files and ones that we actually want in the project. + // This also filters out DLLs coming from .asmdef files in packages. + var assemblies = m_AssemblyNameProvider.GetAssemblies(ShouldFileBePartOfSolution); + + var allAssetProjectParts = GenerateAllAssetProjectParts(); + + var assemblyList = assemblies.ToList(); + + SyncSolution(assemblyList); + + var allProjectAssemblies = RelevantAssembliesForMode(assemblyList).ToList(); + + foreach (Assembly assembly in allProjectAssemblies) + { + SyncProject(assembly, + allAssetProjectParts, + responseFilesData: ParseResponseFileData(assembly), + allProjectAssemblies, +#if UNITY_2020_2_OR_NEWER + assembly.compilerOptions.RoslynAnalyzerDllPaths); +#else + Array.Empty()); +#endif + } + } + + private IEnumerable ParseResponseFileData(Assembly assembly) + { + var systemReferenceDirectories = CompilationPipeline.GetSystemAssemblyDirectories(assembly.compilerOptions.ApiCompatibilityLevel); + + Dictionary responseFilesData = assembly.compilerOptions.ResponseFiles.ToDictionary(x => x, x => m_AssemblyNameProvider.ParseResponseFile( + x, + ProjectDirectory, + systemReferenceDirectories + )); + + Dictionary responseFilesWithErrors = responseFilesData.Where(x => x.Value.Errors.Any()) + .ToDictionary(x => x.Key, x => x.Value); + + if (responseFilesWithErrors.Any()) + { + foreach (var error in responseFilesWithErrors) + foreach (var valueError in error.Value.Errors) + { + Debug.LogError($"{error.Key} Parse Error : {valueError}"); + } + } + + return responseFilesData.Select(x => x.Value); + } + + private Dictionary GenerateAllAssetProjectParts() + { + Dictionary stringBuilders = new Dictionary(); + + foreach (string asset in m_AssemblyNameProvider.GetAllAssetPaths()) + { + // Exclude files coming from packages except if they are internalized. + if (m_AssemblyNameProvider.IsInternalizedPackagePath(asset)) + { + continue; + } + + if (IsSupportedFile(asset) && ScriptingLanguage.None == ScriptingLanguageFor(asset)) + { + // Find assembly the asset belongs to by adding script extension and using compilation pipeline. + var assemblyName = m_AssemblyNameProvider.GetAssemblyNameFromScriptPath(asset + ".cs"); + + if (string.IsNullOrEmpty(assemblyName)) + { + continue; + } + + assemblyName = Path.GetFileNameWithoutExtension(assemblyName); + + if (!stringBuilders.TryGetValue(assemblyName, out var projectBuilder)) + { + projectBuilder = new StringBuilder(); + stringBuilders[assemblyName] = projectBuilder; + } + + projectBuilder.Append(" ").Append(k_WindowsNewline); + } + } + + var result = new Dictionary(); + + foreach (var entry in stringBuilders) + result[entry.Key] = entry.Value.ToString(); + + return result; + } + + private void SyncProject( + Assembly assembly, + Dictionary allAssetsProjectParts, + IEnumerable responseFilesData, + List allProjectAssemblies, + string[] roslynAnalyzerDllPaths) + { + SyncProjectFileIfNotChanged( + ProjectFile(assembly), + ProjectText(assembly, allAssetsProjectParts, responseFilesData, allProjectAssemblies, roslynAnalyzerDllPaths)); + } + + private void SyncProjectFileIfNotChanged(string path, string newContents) + { + if (Path.GetExtension(path) == ".csproj") + { + newContents = OnGeneratedCSProject(path, newContents); + } + + SyncFileIfNotChanged(path, newContents); + } + + private void SyncSolutionFileIfNotChanged(string path, string newContents) + { + newContents = OnGeneratedSlnSolution(path, newContents); + + SyncFileIfNotChanged(path, newContents); + } + + private static IEnumerable GetPostProcessorCallbacks(string name) + { + return TypeCache + .GetTypesDerivedFrom() + .Select(t => t.GetMethod(name, SR.BindingFlags.Public | SR.BindingFlags.NonPublic | SR.BindingFlags.Static)) + .Where(m => m != null); + } - projectBuilder.Append(@" ").Append(k_WindowsNewline); - } + static void OnGeneratedCSProjectFiles() + { + foreach (var method in GetPostProcessorCallbacks(nameof(OnGeneratedCSProjectFiles))) + { + method.Invoke(null, Array.Empty()); + } + } + + private static bool OnPreGeneratingCSProjectFiles() + { + bool result = false; + + foreach (var method in GetPostProcessorCallbacks(nameof(OnPreGeneratingCSProjectFiles))) + { + var retValue = method.Invoke(null, Array.Empty()); + if (method.ReturnType == typeof(bool)) + { + result |= (bool)retValue; + } + } - projectBuilder.Append(ProjectFooter()); - return projectBuilder.ToString(); - } + return result; + } - static string XmlFilename(string path) - { - if (string.IsNullOrEmpty(path)) - return path; + private static string InvokeAssetPostProcessorGenerationCallbacks(string name, string path, string content) + { + foreach (var method in GetPostProcessorCallbacks(name)) + { + var args = new[] { path, content }; + var returnValue = method.Invoke(null, args); + if (method.ReturnType == typeof(string)) + { + // We want to chain content update between invocations + content = (string)returnValue; + } + } + + return content; + } - path = path.Replace(@"%", "%25"); - path = path.Replace(@";", "%3b"); + private static string OnGeneratedCSProject(string path, string content) + { + return InvokeAssetPostProcessorGenerationCallbacks(nameof(OnGeneratedCSProject), path, content); + } - return XmlEscape(path); - } + private static string OnGeneratedSlnSolution(string path, string content) + { + return InvokeAssetPostProcessorGenerationCallbacks(nameof(OnGeneratedSlnSolution), path, content); + } + + private void SyncFileIfNotChanged(string filename, string newContents) + { + try + { + if (m_FileIOProvider.Exists(filename) && newContents == m_FileIOProvider.ReadAllText(filename)) + { + return; + } + } + catch (Exception exception) + { + Debug.LogException(exception); + } + + m_FileIOProvider.WriteAllText(filename, newContents); + } + + private string ProjectText(Assembly assembly, + Dictionary allAssetsProjectParts, + IEnumerable responseFilesData, + List allProjectAssemblies, + string[] roslynAnalyzerDllPaths) + { + var projectBuilder = new StringBuilder(ProjectHeader(assembly, responseFilesData, roslynAnalyzerDllPaths)); + var references = new List(); + + projectBuilder.Append(@" ").Append(k_WindowsNewline); + foreach (string file in assembly.sourceFiles) + { + if (!IsSupportedFile(file)) + continue; + + var extension = Path.GetExtension(file).ToLower(); + var fullFile = EscapedRelativePathFor(file); + if (".dll" != extension) + { + projectBuilder.Append(" ").Append(k_WindowsNewline); + } + else + { + references.Add(fullFile); + } + } + projectBuilder.Append(@" ").Append(k_WindowsNewline); + + projectBuilder.Append(@" ").Append(k_WindowsNewline); + + // Append additional non-script files that should be included in project generation. + if (allAssetsProjectParts.TryGetValue(assembly.name, out var additionalAssetsForProject)) + projectBuilder.Append(additionalAssetsForProject); + + var responseRefs = responseFilesData.SelectMany(x => x.FullPathReferences.Select(r => r)); + var internalAssemblyReferences = assembly.assemblyReferences + .Where(i => !i.sourceFiles.Any(ShouldFileBePartOfSolution)).Select(i => i.outputPath); + var allReferences = + assembly.compiledAssemblyReferences + .Union(responseRefs) + .Union(references) + .Union(internalAssemblyReferences); + + foreach (var reference in allReferences) + { + string fullReference = Path.IsPathRooted(reference) ? reference : Path.Combine(ProjectDirectory, reference); + AppendReference(fullReference, projectBuilder); + } + + projectBuilder.Append(@" ").Append(k_WindowsNewline); + + if (0 < assembly.assemblyReferences.Length) + { + projectBuilder.Append(" ").Append(k_WindowsNewline); + foreach (Assembly reference in assembly.assemblyReferences.Where(i => i.sourceFiles.Any(ShouldFileBePartOfSolution))) + { + projectBuilder.Append(" ").Append(k_WindowsNewline); + projectBuilder.Append(" {").Append(ProjectGuid(reference)).Append("}").Append(k_WindowsNewline); + projectBuilder.Append(" ").Append(reference.name).Append("").Append(k_WindowsNewline); + projectBuilder.Append(" ").Append(k_WindowsNewline); + } + + projectBuilder.Append(@" ").Append(k_WindowsNewline); + } + + projectBuilder.Append(ProjectFooter()); + return projectBuilder.ToString(); + } - static string XmlEscape(string s) - { - return SecurityElement.Escape(s); - } + private static string XmlFilename(string path) + { + if (string.IsNullOrEmpty(path)) + return path; - void AppendReference(string fullReference, StringBuilder projectBuilder) - { - var escapedFullPath = EscapedRelativePathFor(fullReference); - projectBuilder.Append(" ").Append(k_WindowsNewline); - projectBuilder.Append(" ").Append(escapedFullPath).Append("").Append(k_WindowsNewline); - projectBuilder.Append(" ").Append(k_WindowsNewline); - } + path = path.Replace(@"%", "%25"); + path = path.Replace(@";", "%3b"); - public string ProjectFile(Assembly assembly) - { + return XmlEscape(path); + } + + private static string XmlEscape(string s) + { + return SecurityElement.Escape(s); + } + + private void AppendReference(string fullReference, StringBuilder projectBuilder) + { + var escapedFullPath = EscapedRelativePathFor(fullReference); + projectBuilder.Append(" ").Append(k_WindowsNewline); + projectBuilder.Append(" ").Append(escapedFullPath).Append("").Append(k_WindowsNewline); + projectBuilder.Append(" ").Append(k_WindowsNewline); + } + + public string ProjectFile(Assembly assembly) + { return Path.Combine(ProjectDirectory, $"{m_AssemblyNameProvider.GetAssemblyName(assembly.outputPath, assembly.name)}.csproj"); } - private static readonly Regex InvalidCharactersRegexPattern = new Regex(@"\?|&|\*|""|<|>|\||#|%|\^|;" + (VisualStudioEditor.IsWindows ? "" : "|:")); - public string SolutionFile() - { - return Path.Combine(FileUtility.Normalize(ProjectDirectory), $"{InvalidCharactersRegexPattern.Replace(m_ProjectName,"_")}.sln"); - } + private static readonly Regex InvalidCharactersRegexPattern = new Regex(@"\?|&|\*|""|<|>|\||#|%|\^|;" + (VisualStudioEditor.IsWindows ? "" : "|:")); + public string SolutionFile() + { + return Path.Combine(FileUtility.Normalize(ProjectDirectory), $"{InvalidCharactersRegexPattern.Replace(m_ProjectName, "_")}.sln"); + } - string ProjectHeader( - Assembly assembly, - IEnumerable responseFilesData - ) - { - var toolsVersion = "4.0"; - var productVersion = "10.0.20506"; - const string baseDirectory = "."; + internal string VsConfigFile() + { + return Path.Combine(FileUtility.Normalize(ProjectDirectory), ".vsconfig"); + } - var targetFrameworkVersion = "v4.7.1"; - var targetLanguageVersion = "latest"; // danger: latest is not the same absolute value depending on the VS version. + private string ProjectHeader( + Assembly assembly, + IEnumerable responseFilesData, + string[] roslynAnalyzerDllPaths + ) + { + var toolsVersion = "4.0"; + var productVersion = "10.0.20506"; + const string baseDirectory = "."; - if (m_CurrentInstallation != null && m_CurrentInstallation.SupportsCSharp8) - { - // Current VS installation is compatible with C# 8. + var targetFrameworkVersion = "v4.7.1"; + var targetLanguageVersion = "latest"; // danger: latest is not the same absolute value depending on the VS version. + + if (m_CurrentInstallation != null && m_CurrentInstallation.SupportsCSharp8) + { + // Current VS installation is compatible with C# 8. #if !UNITY_2020_2_OR_NEWER - // Unity 2020.2.0a12 added support for C# 8 - // <=2020.1 has no support for C# 8 constructs, so tell the compiler to accept only C# 7.3 or lower. - targetLanguageVersion = "7.3"; + // Unity 2020.2.0a12 added support for C# 8 + // <=2020.1 has no support for C# 8 constructs, so tell the compiler to accept only C# 7.3 or lower. + targetLanguageVersion = "7.3"; #endif - } - - var projectType = ProjectTypeOf(assembly.name); - - var arguments = new object[] - { - toolsVersion, - productVersion, - ProjectGuid(assembly), - XmlFilename(FileUtility.Normalize(InternalEditorUtility.GetEngineAssemblyPath())), - XmlFilename(FileUtility.Normalize(InternalEditorUtility.GetEditorAssemblyPath())), - string.Join(";", assembly.defines.Concat(responseFilesData.SelectMany(x => x.Defines)).Distinct().ToArray()), - MSBuildNamespaceUri, - assembly.name, - assembly.outputPath, - GetRootNamespace(assembly), - targetFrameworkVersion, - targetLanguageVersion, - baseDirectory, - assembly.compilerOptions.AllowUnsafeCode | responseFilesData.Any(x => x.Unsafe), + } + + var projectType = ProjectTypeOf(assembly.name); + + var arguments = new object[] + { + toolsVersion, + productVersion, + ProjectGuid(assembly), + XmlFilename(FileUtility.Normalize(InternalEditorUtility.GetEngineAssemblyPath())), + XmlFilename(FileUtility.Normalize(InternalEditorUtility.GetEditorAssemblyPath())), + string.Join(";", assembly.defines.Concat(responseFilesData.SelectMany(x => x.Defines)).Distinct().ToArray()), + MSBuildNamespaceUri, + assembly.name, + assembly.outputPath, + GetRootNamespace(assembly), + targetFrameworkVersion, + targetLanguageVersion, + baseDirectory, + assembly.compilerOptions.AllowUnsafeCode | responseFilesData.Any(x => x.Unsafe), // flavoring projectType + ":" + (int)projectType, - EditorUserBuildSettings.activeBuildTarget + ":" + (int)EditorUserBuildSettings.activeBuildTarget, - Application.unityVersion, - VisualStudioIntegration.PackageVersion() - }; - - try - { - return string.Format(GetProjectHeaderTemplate(), arguments); - } - catch (Exception) - { - throw new NotSupportedException("Failed creating c# project because the c# project header did not have the correct amount of arguments, which is " + arguments.Length); - } - } - - private enum ProjectType - { - GamePlugins = 3, - Game = 1, - EditorPlugins = 7, - Editor = 5, - } - - private static ProjectType ProjectTypeOf(string fileName) - { - var plugins = fileName.Contains("firstpass"); - var editor = fileName.Contains("Editor"); - - if (plugins && editor) - return ProjectType.EditorPlugins; - if (plugins) - return ProjectType.GamePlugins; - if (editor) - return ProjectType.Editor; - - return ProjectType.Game; - } - - static string GetSolutionText() - { - return string.Join("\r\n", - @"", - @"Microsoft Visual Studio Solution File, Format Version {0}", - @"# Visual Studio {1}", - @"{2}", - @"Global", - @" GlobalSection(SolutionConfigurationPlatforms) = preSolution", - @" Debug|Any CPU = Debug|Any CPU", - @" Release|Any CPU = Release|Any CPU", - @" EndGlobalSection", - @" GlobalSection(ProjectConfigurationPlatforms) = postSolution", - @"{3}", - @" EndGlobalSection", - @"{4}", - @"EndGlobal", - @"").Replace(" ", "\t"); - } - - static string GetProjectFooterTemplate() - { - return string.Join("\r\n", - @" ", - @" ", - @" ", - @"", - @""); - } - - string GetProjectHeaderTemplate() - { - var header = new[] - { - @"", - @"", - @" ", - @" {11}", - @" ", - @" ", - @" Debug", - @" AnyCPU", - @" {1}", - @" 2.0", - @" {9}", - @" {{{2}}}", - @" Library", - @" Properties", - @" {7}", - @" {10}", - @" 512", - @" {12}", - @" ", - @" ", - @" true", - @" full", - @" false", - @" {8}", - @" {5}", - @" prompt", - @" 4", - @" 0169", - @" {13}", - @" ", - @" ", - @" pdbonly", - @" true", - @" Temp\bin\Release\", - @" prompt", - @" 4", - @" 0169", - @" {13}", - @" " - }; - - var forceExplicitReferences = new[] - { - @" ", - @" true", - @" true", - @" false", - @" false", - @" false", - @" " - }; - - var flavoring = new[] - { - @" ", - @" {{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1}};{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}", - @" Package", - @" {17}", - @" {14}", - @" {15}", - @" {16}", - @" " - }; - - var footer = new[] - { - @"" - }; - - var lines = header - .Concat(forceExplicitReferences) - .Concat(flavoring) - .ToList(); - - // Only add analyzer block for compatible Visual Studio - if (m_CurrentInstallation != null && m_CurrentInstallation.SupportsAnalyzers) - { - var analyzers = m_CurrentInstallation.GetAnalyzers(); - if (analyzers != null && analyzers.Length > 0) - { - lines.Add(@" "); - foreach (var analyzer in analyzers) - lines.Add(string.Format(@" ", EscapedRelativePathFor(analyzer))); - lines.Add(@" "); - } - } - - return string.Join("\r\n", lines - .Concat(footer)); - } - - void SyncSolution(IEnumerable assemblies) - { - if (InvalidCharactersRegexPattern.IsMatch(ProjectDirectory)) - Debug.LogWarning("Project path contains special characters, which can be an issue when opening Visual Studio"); - - var solutionFile = SolutionFile(); - var previousSolution = m_FileIOProvider.Exists(solutionFile) ? SolutionParser.ParseSolutionFile(solutionFile, m_FileIOProvider) : null; - SyncSolutionFileIfNotChanged(solutionFile, SolutionText(assemblies, previousSolution)); - } - - string SolutionText(IEnumerable assemblies, Solution previousSolution = null) - { - const string fileversion = "12.00"; - const string vsversion = "15"; - - var relevantAssemblies = RelevantAssembliesForMode(assemblies); - var generatedProjects = ToProjectEntries(relevantAssemblies).ToList(); - - SolutionProperties[] properties = null; - - // First, add all projects generated by Unity to the solution - var projects = new List(); - projects.AddRange(generatedProjects); - - if (previousSolution != null) - { - // Add all projects that were previously in the solution and that are not generated by Unity, nor generated in the project root directory - var externalProjects = previousSolution.Projects - .Where(p => p.IsSolutionFolderProjectFactory() || !FileUtility.IsFileInProjectDirectory(p.FileName)) - .Where(p => generatedProjects.All(gp => gp.FileName != p.FileName)); - - projects.AddRange(externalProjects); - properties = previousSolution.Properties; - } - - string propertiesText = GetPropertiesText(properties); - string projectEntriesText = GetProjectEntriesText(projects); - - // do not generate configurations for SolutionFolders - var configurableProjects = projects.Where(p => !p.IsSolutionFolderProjectFactory()); - string projectConfigurationsText = string.Join(k_WindowsNewline, configurableProjects.Select(p => GetProjectActiveConfigurations(p.ProjectGuid)).ToArray()); - - return string.Format(GetSolutionText(), fileversion, vsversion, projectEntriesText, projectConfigurationsText, propertiesText); - } - - static IEnumerable RelevantAssembliesForMode(IEnumerable assemblies) - { - return assemblies.Where(i => ScriptingLanguage.CSharp == ScriptingLanguageFor(i)); - } - - private string GetPropertiesText(SolutionProperties[] array) - { - if (array == null || array.Length == 0) - { - // HideSolution by default - array = new SolutionProperties[] { - new SolutionProperties() { - Name = "SolutionProperties", - Type = "preSolution", - Entries = new List>() { new KeyValuePair ("HideSolutionNode", "FALSE") } - } - }; - } - var result = new StringBuilder(); - - for (var i = 0; i 0) - result.Append(k_WindowsNewline); - - var properties = array[i]; - - result.Append($"\tGlobalSection({properties.Name}) = {properties.Type}"); - result.Append(k_WindowsNewline); - - foreach (var entry in properties.Entries) + EditorUserBuildSettings.activeBuildTarget + ":" + (int)EditorUserBuildSettings.activeBuildTarget, + Application.unityVersion, + VisualStudioIntegration.PackageVersion() + }; + + try + { +#if UNITY_2020_2_OR_NEWER + return string.Format(GetProjectHeaderTemplate(roslynAnalyzerDllPaths, assembly.compilerOptions.RoslynAnalyzerRulesetPath), arguments); +#else + return string.Format(GetProjectHeaderTemplate(Array.Empty(), null), arguments); +#endif + } + catch (Exception) + { + throw new NotSupportedException("Failed creating c# project because the c# project header did not have the correct amount of arguments, which is " + arguments.Length); + } + } + + private enum ProjectType + { + GamePlugins = 3, + Game = 1, + EditorPlugins = 7, + Editor = 5, + } + + private static ProjectType ProjectTypeOf(string fileName) + { + var plugins = fileName.Contains("firstpass"); + var editor = fileName.Contains("Editor"); + + if (plugins && editor) + return ProjectType.EditorPlugins; + if (plugins) + return ProjectType.GamePlugins; + if (editor) + return ProjectType.Editor; + + return ProjectType.Game; + } + + private static string GetSolutionText() + { + return string.Join("\r\n", + @"", + @"Microsoft Visual Studio Solution File, Format Version {0}", + @"# Visual Studio {1}", + @"{2}", + @"Global", + @" GlobalSection(SolutionConfigurationPlatforms) = preSolution", + @" Debug|Any CPU = Debug|Any CPU", + @" Release|Any CPU = Release|Any CPU", + @" EndGlobalSection", + @" GlobalSection(ProjectConfigurationPlatforms) = postSolution", + @"{3}", + @" EndGlobalSection", + @"{4}", + @"EndGlobal", + @"").Replace(" ", "\t"); + } + + private static string GetProjectFooterTemplate() + { + return string.Join("\r\n", + @" ", + @" ", + @" ", + @"", + @""); + } + + private string GetProjectHeaderTemplate(string[] roslynAnalyzerDllPaths, string roslynAnalyzerRulesetPath) + { + var header = new[] + { + @"", + @"", + @" ", + @" {11}", + @" ", + @" ", + @" Debug", + @" AnyCPU", + @" {1}", + @" 2.0", + @" {9}", + @" {{{2}}}", + @" Library", + @" Properties", + @" {7}", + @" {10}", + @" 512", + @" {12}", + @" ", + @" ", + @" true", + @" full", + @" false", + @" {8}", + @" {5}", + @" prompt", + @" 4", + @" 0169", + @" {13}", + @" ", + @" ", + @" pdbonly", + @" true", + @" Temp\bin\Release\", + @" prompt", + @" 4", + @" 0169", + @" {13}", + @" " + }; + + var forceExplicitReferences = new[] + { + @" ", + @" true", + @" true", + @" false", + @" false", + @" false", + @" " + }; + + var flavoring = new[] + { + @" ", + @" {{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1}};{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}", + @" Package", + @" {17}", + @" {14}", + @" {15}", + @" {16}", + @" " + }; + + var footer = new[] + { + @"" + }; + + var lines = header.Concat(forceExplicitReferences).Concat(flavoring).ToList(); + + // Only add analyzer block for compatible Visual Studio + if (m_CurrentInstallation != null && m_CurrentInstallation.SupportsAnalyzers) + { +#if UNITY_2020_2_OR_NEWER + if (roslynAnalyzerRulesetPath != null) { - result.Append($"\t\t{entry.Key} = {entry.Value}"); - result.Append(k_WindowsNewline); + lines.Add(@" "); + lines.Add($" {roslynAnalyzerRulesetPath}"); + lines.Add(@" "); } +#endif - result.Append("\tEndGlobalSection"); - } - - return result.ToString(); - } - - /// - /// Get a Project("{guid}") = "MyProject", "MyProject.unityproj", "{projectguid}" - /// entry for each relevant language - /// - string GetProjectEntriesText(IEnumerable entries) - { - var projectEntries = entries.Select(entry => string.Format( - m_SolutionProjectEntryTemplate, - entry.ProjectFactoryGuid, entry.Name, entry.FileName, entry.ProjectGuid, entry.Metadata - )); - - return string.Join(k_WindowsNewline, projectEntries.ToArray()); - } - - IEnumerable ToProjectEntries(IEnumerable assemblies) - { - foreach (var assembly in assemblies) - yield return new SolutionProjectEntry() - { - ProjectFactoryGuid = SolutionGuid(assembly), - Name = assembly.name, - FileName = Path.GetFileName(ProjectFile(assembly)), - ProjectGuid = ProjectGuid(assembly), - Metadata = k_WindowsNewline - }; - } - - /// - /// Generate the active configuration string for a given project guid - /// - string GetProjectActiveConfigurations(string projectGuid) - { - return string.Format( - m_SolutionProjectConfigurationTemplate, - projectGuid); - } - - string EscapedRelativePathFor(string file) - { - var projectDir = FileUtility.Normalize(ProjectDirectory); - file = FileUtility.Normalize(file); - var path = SkipPathPrefix(file, projectDir); - - var packageInfo = m_AssemblyNameProvider.FindForAssetPath(path.Replace('\\', '/')); - if (packageInfo != null) { - // We have to normalize the path, because the PackageManagerRemapper assumes - // dir seperators will be os specific. - var absolutePath = Path.GetFullPath(FileUtility.Normalize(path)); - path = SkipPathPrefix(absolutePath, projectDir); - } - - return XmlFilename(path); - } - - static string SkipPathPrefix(string path, string prefix) - { - if (path.StartsWith($"{prefix}{Path.DirectorySeparatorChar}") && (path.Length > prefix.Length)) - return path.Substring(prefix.Length + 1); - return path; - } - - static string ProjectFooter() - { - return GetProjectFooterTemplate(); - } - - static string GetProjectExtension() - { - return ".csproj"; - } - - string ProjectGuid(Assembly assembly) - { - return m_GUIDGenerator.ProjectGuid( + string[] analyzers = m_CurrentInstallation.GetAnalyzers(); + string[] allAnalyzers = analyzers != null ? analyzers.Concat(roslynAnalyzerDllPaths).ToArray() : roslynAnalyzerDllPaths; + + if (allAnalyzers.Any()) + { + lines.Add(@" "); + foreach (var analyzer in allAnalyzers) + { + lines.Add($@" "); + } + lines.Add(@" "); + } + } + + return string.Join("\r\n", lines.Concat(footer)); + } + + private void SyncSolution(IEnumerable assemblies) + { + if (InvalidCharactersRegexPattern.IsMatch(ProjectDirectory)) + Debug.LogWarning("Project path contains special characters, which can be an issue when opening Visual Studio"); + + var solutionFile = SolutionFile(); + var previousSolution = m_FileIOProvider.Exists(solutionFile) ? SolutionParser.ParseSolutionFile(solutionFile, m_FileIOProvider) : null; + SyncSolutionFileIfNotChanged(solutionFile, SolutionText(assemblies, previousSolution)); + } + + private string SolutionText(IEnumerable assemblies, Solution previousSolution = null) + { + const string fileversion = "12.00"; + const string vsversion = "15"; + + var relevantAssemblies = RelevantAssembliesForMode(assemblies); + var generatedProjects = ToProjectEntries(relevantAssemblies).ToList(); + + SolutionProperties[] properties = null; + + // First, add all projects generated by Unity to the solution + var projects = new List(); + projects.AddRange(generatedProjects); + + if (previousSolution != null) + { + // Add all projects that were previously in the solution and that are not generated by Unity, nor generated in the project root directory + var externalProjects = previousSolution.Projects + .Where(p => p.IsSolutionFolderProjectFactory() || !FileUtility.IsFileInProjectDirectory(p.FileName)) + .Where(p => generatedProjects.All(gp => gp.FileName != p.FileName)); + + projects.AddRange(externalProjects); + properties = previousSolution.Properties; + } + + string propertiesText = GetPropertiesText(properties); + string projectEntriesText = GetProjectEntriesText(projects); + + // do not generate configurations for SolutionFolders + var configurableProjects = projects.Where(p => !p.IsSolutionFolderProjectFactory()); + string projectConfigurationsText = string.Join(k_WindowsNewline, configurableProjects.Select(p => GetProjectActiveConfigurations(p.ProjectGuid)).ToArray()); + + return string.Format(GetSolutionText(), fileversion, vsversion, projectEntriesText, projectConfigurationsText, propertiesText); + } + + private static IEnumerable RelevantAssembliesForMode(IEnumerable assemblies) + { + return assemblies.Where(i => ScriptingLanguage.CSharp == ScriptingLanguageFor(i)); + } + + private static string GetPropertiesText(SolutionProperties[] array) + { + if (array == null || array.Length == 0) + { + // HideSolution by default + array = new SolutionProperties[] { + new SolutionProperties() { + Name = "SolutionProperties", + Type = "preSolution", + Entries = new List>() { new KeyValuePair ("HideSolutionNode", "FALSE") } + } + }; + } + var result = new StringBuilder(); + + for (var i = 0; i < array.Length; i++) + { + if (i > 0) + result.Append(k_WindowsNewline); + + var properties = array[i]; + + result.Append($"\tGlobalSection({properties.Name}) = {properties.Type}"); + result.Append(k_WindowsNewline); + + foreach (var entry in properties.Entries) + { + result.Append($"\t\t{entry.Key} = {entry.Value}"); + result.Append(k_WindowsNewline); + } + + result.Append("\tEndGlobalSection"); + } + + return result.ToString(); + } + + /// + /// Get a Project("{guid}") = "MyProject", "MyProject.unityproj", "{projectguid}" + /// entry for each relevant language + /// + private string GetProjectEntriesText(IEnumerable entries) + { + var projectEntries = entries.Select(entry => string.Format( + m_SolutionProjectEntryTemplate, + entry.ProjectFactoryGuid, entry.Name, entry.FileName, entry.ProjectGuid, entry.Metadata + )); + + return string.Join(k_WindowsNewline, projectEntries.ToArray()); + } + + private IEnumerable ToProjectEntries(IEnumerable assemblies) + { + foreach (var assembly in assemblies) + yield return new SolutionProjectEntry() + { + ProjectFactoryGuid = SolutionGuid(assembly), + Name = assembly.name, + FileName = Path.GetFileName(ProjectFile(assembly)), + ProjectGuid = ProjectGuid(assembly), + Metadata = k_WindowsNewline + }; + } + + /// + /// Generate the active configuration string for a given project guid + /// + private string GetProjectActiveConfigurations(string projectGuid) + { + return string.Format( + m_SolutionProjectConfigurationTemplate, + projectGuid); + } + + private string EscapedRelativePathFor(string file) + { + var projectDir = FileUtility.Normalize(ProjectDirectory); + file = FileUtility.Normalize(file); + var path = SkipPathPrefix(file, projectDir); + + var packageInfo = m_AssemblyNameProvider.FindForAssetPath(path.Replace('\\', '/')); + if (packageInfo != null) + { + // We have to normalize the path, because the PackageManagerRemapper assumes + // dir seperators will be os specific. + var absolutePath = Path.GetFullPath(FileUtility.Normalize(path)); + path = SkipPathPrefix(absolutePath, projectDir); + } + + return XmlFilename(path); + } + + private static string SkipPathPrefix(string path, string prefix) + { + if (path.StartsWith($"{prefix}{Path.DirectorySeparatorChar}") && (path.Length > prefix.Length)) + return path.Substring(prefix.Length + 1); + return path; + } + + private static string ProjectFooter() + { + return GetProjectFooterTemplate(); + } + + static string GetProjectExtension() + { + return ".csproj"; + } + + private string ProjectGuid(Assembly assembly) + { + return m_GUIDGenerator.ProjectGuid( m_ProjectName, m_AssemblyNameProvider.GetAssemblyName(assembly.outputPath, assembly.name)); } - string SolutionGuid(Assembly assembly) - { - return m_GUIDGenerator.SolutionGuid(m_ProjectName, ScriptingLanguageFor(assembly)); - } + private string SolutionGuid(Assembly assembly) + { + return m_GUIDGenerator.SolutionGuid(m_ProjectName, ScriptingLanguageFor(assembly)); + } - static string GetRootNamespace(Assembly assembly) - { - #if UNITY_2020_2_OR_NEWER + private static string GetRootNamespace(Assembly assembly) + { +#if UNITY_2020_2_OR_NEWER return assembly.rootNamespace; #else - return EditorSettings.projectGenerationRootNamespace; + return EditorSettings.projectGenerationRootNamespace; #endif - } - } - - public static class SolutionGuidGenerator - { - public static string GuidForProject(string projectName) - { - return ComputeGuidHashFor(projectName + "salt"); - } - - public static string GuidForSolution(string projectName, ScriptingLanguage language) - { - if (language == ScriptingLanguage.CSharp) - { - // GUID for a C# class library: http://www.codeproject.com/Reference/720512/List-of-Visual-Studio-Project-Type-GUIDs - return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"; - } - - return ComputeGuidHashFor(projectName); - } - - static string ComputeGuidHashFor(string input) - { - var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(input)); - return HashAsGuid(HashToString(hash)); - } - - static string HashAsGuid(string hash) - { - var guid = hash.Substring(0, 8) + "-" + hash.Substring(8, 4) + "-" + hash.Substring(12, 4) + "-" + hash.Substring(16, 4) + "-" + hash.Substring(20, 12); - return guid.ToUpper(); - } - - static string HashToString(byte[] bs) - { - var sb = new StringBuilder(); - foreach (byte b in bs) - sb.Append(b.ToString("x2")); - return sb.ToString(); - } - } + } + } + + public static class SolutionGuidGenerator + { + public static string GuidForProject(string projectName) + { + return ComputeGuidHashFor(projectName + "salt"); + } + + public static string GuidForSolution(string projectName, ScriptingLanguage language) + { + if (language == ScriptingLanguage.CSharp) + { + // GUID for a C# class library: http://www.codeproject.com/Reference/720512/List-of-Visual-Studio-Project-Type-GUIDs + return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"; + } + + return ComputeGuidHashFor(projectName); + } + + private static string ComputeGuidHashFor(string input) + { + var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(input)); + return HashAsGuid(HashToString(hash)); + } + + private static string HashAsGuid(string hash) + { + var guid = hash.Substring(0, 8) + "-" + hash.Substring(8, 4) + "-" + hash.Substring(12, 4) + "-" + hash.Substring(16, 4) + "-" + hash.Substring(20, 12); + return guid.ToUpper(); + } + + private static string HashToString(byte[] bs) + { + var sb = new StringBuilder(); + foreach (byte b in bs) + sb.Append(b.ToString("x2")); + return sb.ToString(); + } + } } diff --git a/Editor/ProjectGeneration/ProjectGenerationFlag.cs b/Editor/ProjectGeneration/ProjectGenerationFlag.cs index fd3438c..bbcc369 100644 --- a/Editor/ProjectGeneration/ProjectGenerationFlag.cs +++ b/Editor/ProjectGeneration/ProjectGenerationFlag.cs @@ -1,8 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Unity Technologies. + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +using System; namespace Microsoft.Unity.VisualStudio.Editor { diff --git a/Editor/SolutionParser.cs b/Editor/SolutionParser.cs index 81f7ab2..35c9346 100644 --- a/Editor/SolutionParser.cs +++ b/Editor/SolutionParser.cs @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ using System.Collections.Generic; -using System.IO; using System.Text.RegularExpressions; namespace Microsoft.Unity.VisualStudio.Editor diff --git a/Editor/VisualStudioEditor.cs b/Editor/VisualStudioEditor.cs index 0032120..a102468 100644 --- a/Editor/VisualStudioEditor.cs +++ b/Editor/VisualStudioEditor.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; using UnityEditor; using UnityEngine; using Unity.CodeEditor; @@ -18,14 +17,14 @@ namespace Microsoft.Unity.VisualStudio.Editor [InitializeOnLoad] public class VisualStudioEditor : IExternalCodeEditor { - private static readonly VisualStudioInstallation[] _installations; + private static readonly IVisualStudioInstallation[] _installations; internal static bool IsOSX => Application.platform == RuntimePlatform.OSXEditor; - internal static bool IsWindows => !IsOSX && Path.DirectorySeparatorChar == '\\' && Environment.NewLine == "\r\n"; + internal static bool IsWindows => !IsOSX && Path.DirectorySeparatorChar == FileUtility.WinSeparator && Environment.NewLine == "\r\n"; CodeEditor.Installation[] IExternalCodeEditor.Installations => _installations .Select(i => i.ToCodeEditorInstallation()) - .ToArray(); + .ToArray(); private readonly IGenerator _generator = new ProjectGeneration(); @@ -39,7 +38,7 @@ static VisualStudioEditor() } catch (Exception ex) { - UnityEngine.Debug.Log($"Error detecting Visual Studio installations: {ex}"); + UnityEngine.Debug.LogError($"Error detecting Visual Studio installations: {ex}"); _installations = Array.Empty(); } @@ -64,7 +63,7 @@ public void Initialize(string editorInstallationPath) { } - internal bool TryGetVisualStudioInstallationForPath(string editorPath, out VisualStudioInstallation installation) + internal virtual bool TryGetVisualStudioInstallationForPath(string editorPath, out IVisualStudioInstallation installation) { // lookup for well known installations foreach (var candidate in _installations) @@ -79,7 +78,7 @@ internal bool TryGetVisualStudioInstallationForPath(string editorPath, out Visua return Discovery.TryDiscoverInstallation(editorPath, out installation); } - public bool TryGetInstallationForPath(string editorPath, out CodeEditor.Installation installation) + public virtual bool TryGetInstallationForPath(string editorPath, out CodeEditor.Installation installation) { var result = TryGetVisualStudioInstallationForPath(editorPath, out var vsi); installation = vsi == null ? default : vsi.ToCodeEditorInstallation(); @@ -117,14 +116,14 @@ public void OnGUI() } void RegenerateProjectFiles() - { - var rect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(new GUILayoutOption[] {})); - rect.width = 252; - if (GUI.Button(rect, "Regenerate project files")) - { - _generator.Sync(); - } - } + { + var rect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(new GUILayoutOption[] { })); + rect.width = 252; + if (GUI.Button(rect, "Regenerate project files")) + { + _generator.Sync(); + } + } void SettingsButton(ProjectGenerationFlag preference, string guiMessage, string toolTip) { @@ -143,8 +142,12 @@ public void SyncIfNeeded(string[] addedFiles, string[] deletedFiles, string[] mo foreach (var file in importedFiles.Where(a => Path.GetExtension(a) == ".pdb")) { var pdbFile = FileUtility.GetAssetFullPath(file); - var asmFile = Path.ChangeExtension(pdbFile, ".dll"); + // skip Unity packages like com.unity.ext.nunit + if (pdbFile.IndexOf($"{Path.DirectorySeparatorChar}com.unity.", StringComparison.OrdinalIgnoreCase) > 0) + continue; + + var asmFile = Path.ChangeExtension(pdbFile, ".dll"); if (!File.Exists(asmFile) || !Image.IsAssembly(asmFile)) continue; @@ -176,11 +179,31 @@ bool IsSupportedPath(string path) return false; } + private static void CheckCurrentEditorInstallation() + { + var editorPath = CodeEditor.CurrentEditorInstallation; + try + { + if (Discovery.TryDiscoverInstallation(editorPath, out _)) + return; + } + catch (IOException) + { + } + + UnityEngine.Debug.LogWarning($"Visual Studio executable {editorPath} is not found. Please change your settings in Edit > Preferences > External Tools."); + } + public bool OpenProject(string path, int line, int column) { + CheckCurrentEditorInstallation(); + if (!IsSupportedPath(path)) return false; + if (!IsProjectGeneratedFor(path, out var missingFlag)) + UnityEngine.Debug.LogWarning($"You are trying to open {path} outside a generated project. This might cause problems with IntelliSense and debugging. To avoid this, you can change your .csproj preferences in Edit > Preferences > External Tools and enable {GetProjectGenerationFlagDescription(missingFlag)} generation."); + if (IsOSX) return OpenOSXApp(path, line, column); @@ -190,6 +213,67 @@ public bool OpenProject(string path, int line, int column) return false; } + private static string GetProjectGenerationFlagDescription(ProjectGenerationFlag flag) + { + switch (flag) + { + case ProjectGenerationFlag.BuiltIn: + return "Built-in packages"; + case ProjectGenerationFlag.Embedded: + return "Embedded packages"; + case ProjectGenerationFlag.Git: + return "Git packages"; + case ProjectGenerationFlag.Local: + return "Local packages"; + case ProjectGenerationFlag.LocalTarBall: + return "Local tarball"; + case ProjectGenerationFlag.PlayerAssemblies: + return "Player projects"; + case ProjectGenerationFlag.Registry: + return "Registry packages"; + case ProjectGenerationFlag.Unknown: + return "Packages from unknown sources"; + case ProjectGenerationFlag.None: + default: + return string.Empty; + } + } + + private bool IsProjectGeneratedFor(string path, out ProjectGenerationFlag missingFlag) + { + missingFlag = ProjectGenerationFlag.None; + + // No need to check when opening the whole solution + if (string.IsNullOrEmpty(path)) + return true; + + // We only want to check for cs scripts + if (ProjectGeneration.ScriptingLanguageFor(path) != ScriptingLanguage.CSharp) + return true; + + // Even on windows, the package manager requires relative path + unix style separators for queries + var basePath = _generator.ProjectDirectory; + var relativePath = FileUtility + .NormalizeWindowsToUnix(path) + .Replace(basePath, string.Empty) + .Trim(FileUtility.UnixSeparator); + + var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(relativePath); + if (packageInfo == null) + return true; + + var source = packageInfo.source; + if (!Enum.TryParse(source.ToString(), out var flag)) + return true; + + if (_generator.AssemblyNameProvider.ProjectGenerationFlag.HasFlag(flag)) + return true; + + // Return false if we found a source not flagged for generation + missingFlag = flag; + return false; + } + private bool OpenWindowsApp(string path, int line) { var progpath = FileUtility diff --git a/Editor/VisualStudioInstallation.cs b/Editor/VisualStudioInstallation.cs index 9972796..2b1d5f7 100644 --- a/Editor/VisualStudioInstallation.cs +++ b/Editor/VisualStudioInstallation.cs @@ -10,7 +10,16 @@ namespace Microsoft.Unity.VisualStudio.Editor { - internal class VisualStudioInstallation + internal interface IVisualStudioInstallation + { + string Path { get; } + bool SupportsAnalyzers { get; } + bool SupportsCSharp8 { get; } + string[] GetAnalyzers(); + CodeEditor.Installation ToCodeEditorInstallation(); + } + + internal class VisualStudioInstallation : IVisualStudioInstallation { public string Name { get; set; } public string Path { get; set; } diff --git a/Editor/VisualStudioIntegration.cs b/Editor/VisualStudioIntegration.cs index 8c1bcc3..a07cdd1 100644 --- a/Editor/VisualStudioIntegration.cs +++ b/Editor/VisualStudioIntegration.cs @@ -33,8 +33,9 @@ static VisualStudioIntegration() // - if another application is using this port with exclusive access // - or if the firewall is not properly configured var messagingPort = MessagingPort(); - - try { + + try + { _messager = Messager.BindTo(messagingPort); _messager.ReceiveMessage += ReceiveMessage; } @@ -155,7 +156,7 @@ private static void Refresh() // If the user disabled auto-refresh in Unity, do not try to force refresh the Asset database if (!EditorPrefs.GetBool("kAutoRefresh", true)) return; - + RunOnceOnUpdate(AssetDatabase.Refresh); } diff --git a/package.json b/package.json index e380308..d7fbb87 100644 --- a/package.json +++ b/package.json @@ -2,18 +2,18 @@ "name": "com.unity.ide.visualstudio", "displayName": "Visual Studio Editor", "description": "Code editor integration for supporting Visual Studio as code editor for unity. Adds support for generating csproj files for intellisense purposes, auto discovery of installations, etc.", - "version": "2.0.3", + "version": "2.0.5", "unity": "2020.1", "unityRelease": "0a12", "relatedPackages": { - "com.unity.ide.visualstudio.tests": "2.0.3" + "com.unity.ide.visualstudio.tests": "2.0.5" }, "upmCi": { - "footprint": "a528d76d0398bf543d3597af18e87e2f3a13d40a" + "footprint": "848c02b3f0fe476a599004cd972346a89e39d26f" }, "repository": { "url": "https://github.cds.internal.unity3d.com/unity/com.unity.ide.visualstudio.git", "type": "git", - "revision": "869804bff6e99d0d0e9c1867aebaa070fad875e5" + "revision": "83ca94e82bb6da515dc57e0d860b6b2224f56991" } }