From b0f2251c48a4498b340e6297bf915828e6c349a9 Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity> Date: Tue, 4 May 2021 00:00:00 +0000 Subject: [PATCH] com.unity.ide.visualstudio@2.0.9 ## [2.0.9] - 2021-05-04 Project generation: Added support for CLI. Integration: Improved performance when discovering Visual Studio installations. Warn when legacy assemblies are present in the project. Warn when the package version is not up-to-date. --- CHANGELOG.md | 31 ++++-- Editor/AsyncOperation.cs | 76 +++++++++++++++ Editor/AsyncOperation.cs.meta | 11 +++ Editor/Cli.cs | 88 ++++++++++++++++++ Editor/Cli.cs.meta | 11 +++ Editor/Discovery.cs | 18 ++-- Editor/KnownAssemblies.cs | 14 +++ Editor/KnownAssemblies.cs.meta | 11 +++ .../Contents/Info.plist | 14 +-- .../Contents/MacOS/AppleEventIntegration | Bin 55040 -> 153488 bytes Editor/ProjectGeneration/ProjectGeneration.cs | 4 +- Editor/VisualStudioEditor.cs | 55 ++++++----- Editor/VisualStudioIntegration.cs | 60 ++++++++++++ package.json | 8 +- 14 files changed, 347 insertions(+), 54 deletions(-) create mode 100644 Editor/AsyncOperation.cs create mode 100644 Editor/AsyncOperation.cs.meta create mode 100644 Editor/Cli.cs create mode 100644 Editor/Cli.cs.meta create mode 100644 Editor/KnownAssemblies.cs create mode 100644 Editor/KnownAssemblies.cs.meta diff --git a/CHANGELOG.md b/CHANGELOG.md index 15701ec..32f1b41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,34 @@ # Code Editor Package for Visual Studio +## [2.0.9] - 2021-05-04 + +Project generation: + +Added support for CLI. + +Integration: + +Improved performance when discovering Visual Studio installations. +Warn when legacy assemblies are present in the project. +Warn when the package version is not up-to-date. + + ## [2.0.8] - 2021-04-09 Project generation: -Improved generation performance (especially with DOTS enabled projects). -Improved stability. -Updated Analyzers lookup strategy. -Fixed .vsconfig file not generated when using "regenerate all". +- Improved generation performance (especially with DOTS enabled projects). +- Improved stability. +- Updated Analyzers lookup strategy. +- Fixed .vsconfig file not generated when using "regenerate all". -Integration +Integration: -Improved automation plugins. +- Improved automation plugins. -Documentation - -Open sourced automation plugins. +Documentation: +- Open sourced automation plugins. ## [2.0.7] - 2021-02-02 @@ -24,7 +36,6 @@ Integration: - Remove com.unity.nuget.newtonsoft-json dependency in favor of the built-in JsonUtility for the VS Test Runner. - ## [2.0.6] - 2021-01-20 Project generation: diff --git a/Editor/AsyncOperation.cs b/Editor/AsyncOperation.cs new file mode 100644 index 0000000..0644347 --- /dev/null +++ b/Editor/AsyncOperation.cs @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * 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.Threading; + +namespace Microsoft.Unity.VisualStudio.Editor +{ + internal class AsyncOperation + { + private readonly Func _producer; + private readonly ManualResetEventSlim _resetEvent; + + private T _result; + private Exception _exception; + + private AsyncOperation(Func producer) + { + _producer = producer; + _resetEvent = new ManualResetEventSlim(initialState: false); + } + + public static AsyncOperation Run(Func producer) + { + var task = new AsyncOperation(producer); + task.Run(); + return task; + } + + private void Run() + { + ThreadPool.QueueUserWorkItem(_ => + { + try + { + _result = _producer(); + } + catch (Exception e) + { + _exception = e; + } + finally + { + _resetEvent.Set(); + } + }); + } + + private void CheckCompletion() + { + if (!_resetEvent.IsSet) + _resetEvent.Wait(); + } + + + public T Result + { + get + { + CheckCompletion(); + return _result; + } + } + + public Exception Exception + { + get + { + CheckCompletion(); + return _exception; + } + } + } +} diff --git a/Editor/AsyncOperation.cs.meta b/Editor/AsyncOperation.cs.meta new file mode 100644 index 0000000..e304746 --- /dev/null +++ b/Editor/AsyncOperation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6c8b2f6152bd1348ae35f9f95719f75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Cli.cs b/Editor/Cli.cs new file mode 100644 index 0000000..f941551 --- /dev/null +++ b/Editor/Cli.cs @@ -0,0 +1,88 @@ +/*--------------------------------------------------------------------------------------------- + * 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.Linq; +using Unity.CodeEditor; + +namespace Microsoft.Unity.VisualStudio.Editor +{ + internal static class Cli + { + internal static void Log(string message) + { + // Use writeline here, instead of UnityEngine.Debug.Log to not include the stacktrace in the editor.log + Console.WriteLine($"[VisualStudio.Editor.{nameof(Cli)}] {message}"); + } + + internal static string GetInstallationDetails(IVisualStudioInstallation installation) + { + return $"{installation.ToCodeEditorInstallation().Name} Path:{installation.Path}, LanguageVersionSupport:{installation.LatestLanguageVersionSupported} AnalyzersSupport:{installation.SupportsAnalyzers}"; + } + + internal static void GenerateSolutionWith(VisualStudioEditor vse, string installationPath) + { + if (vse != null && vse.TryGetVisualStudioInstallationForPath(installationPath, searchInstallations: true, out var vsi)) + { + Log($"Using {GetInstallationDetails(vsi)}"); + vse.SyncAll(); + } + else + { + Log($"No Visual Studio installation found in ${installationPath}!"); + } + } + + internal static void GenerateSolution() + { + if (CodeEditor.CurrentEditor is VisualStudioEditor vse) + { + Log($"Using default editor settings for Visual Studio installation"); + GenerateSolutionWith(vse, CodeEditor.CurrentEditorInstallation); + } + else + { + Log($"Visual Studio is not set as your default editor, looking for installations"); + try + { + var installations = Discovery + .GetVisualStudioInstallations() + .Cast() + .OrderByDescending(vsi => !vsi.IsPrerelease) + .ThenBy(vsi => vsi.Version) + .ToArray(); + + foreach(var vsi in installations) + { + Log($"Detected {GetInstallationDetails(vsi)}"); + } + + var installation = installations + .FirstOrDefault(); + + if (installation != null) + { + var current = CodeEditor.CurrentEditorInstallation; + try + { + CodeEditor.SetExternalScriptEditor(installation.Path); + GenerateSolutionWith(CodeEditor.CurrentEditor as VisualStudioEditor, installation.Path); + } + finally + { + CodeEditor.SetExternalScriptEditor(current); + } + } else + { + Log($"No Visual Studio installation found!"); + } + } + catch (Exception ex) + { + Log($"Error detecting Visual Studio installations: {ex}"); + } + } + } + } +} diff --git a/Editor/Cli.cs.meta b/Editor/Cli.cs.meta new file mode 100644 index 0000000..74d2884 --- /dev/null +++ b/Editor/Cli.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7b5530092b3a7646bdc7865f1f6ee94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Discovery.cs b/Editor/Discovery.cs index 893ed3a..6c4a676 100644 --- a/Editor/Discovery.cs +++ b/Editor/Discovery.cs @@ -6,10 +6,10 @@ using System; using System.IO; using System.Collections.Generic; -using UnityEngine; using System.Diagnostics; using System.Text.RegularExpressions; using System.Linq; +using UnityEngine; namespace Microsoft.Unity.VisualStudio.Editor { @@ -17,6 +17,14 @@ namespace Microsoft.Unity.VisualStudio.Editor { internal const string ManagedWorkload = "Microsoft.VisualStudio.Workload.ManagedGame"; + internal static string _vsWherePath; + + public static void FindVSWhere() + { + _vsWherePath = FileUtility + .FindPackageAssetFullPath("VSWhere a:packages", "vswhere.exe") + .FirstOrDefault(); + } public static IEnumerable GetVisualStudioInstallations() { @@ -37,7 +45,7 @@ namespace Microsoft.Unity.VisualStudio.Editor } } - private static bool IsCandidateToDiscovery(string path) + private static bool IsCandidateForDiscovery(string path) { if (File.Exists(path) && VisualStudioEditor.IsWindows && Regex.IsMatch(path, "devenv.exe$", RegexOptions.IgnoreCase)) return true; @@ -55,7 +63,7 @@ namespace Microsoft.Unity.VisualStudio.Editor if (string.IsNullOrEmpty(editorPath)) return false; - if (!IsCandidateToDiscovery(editorPath)) + if (!IsCandidateForDiscovery(editorPath)) return false; // On windows we use the executable directly, so we can query extra information @@ -131,9 +139,7 @@ namespace Microsoft.Unity.VisualStudio.Editor private static IEnumerable QueryVsWhere() { - var progpath = FileUtility - .FindPackageAssetFullPath("VSWhere a:packages", "vswhere.exe") - .FirstOrDefault(); + var progpath = _vsWherePath; if (string.IsNullOrWhiteSpace(progpath)) return Enumerable.Empty(); diff --git a/Editor/KnownAssemblies.cs b/Editor/KnownAssemblies.cs new file mode 100644 index 0000000..2cd7ba1 --- /dev/null +++ b/Editor/KnownAssemblies.cs @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * 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 +{ + internal static class KnownAssemblies + { + public const string Bridge = "SyntaxTree.VisualStudio.Unity.Bridge"; + public const string Messaging = "SyntaxTree.VisualStudio.Unity.Messaging"; + public const string UnityVS = "UnityVS.VersionSpecific"; + } +} diff --git a/Editor/KnownAssemblies.cs.meta b/Editor/KnownAssemblies.cs.meta new file mode 100644 index 0000000..9e2d1ca --- /dev/null +++ b/Editor/KnownAssemblies.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cbccb6292dce08a489e6e742243154e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist b/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist index 9d34eaf..3d8975b 100644 --- a/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist +++ b/Editor/Plugins/AppleEventIntegration.bundle/Contents/Info.plist @@ -3,7 +3,7 @@ BuildMachineOSBuild - 19H2 + 19H1030 CFBundleDevelopmentRegion en CFBundleExecutable @@ -27,19 +27,19 @@ DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild - 12A7300 + 12D4e DTPlatformName macosx DTPlatformVersion - 10.15.6 + 11.1 DTSDKBuild - 19G68 + 20C63 DTSDKName - macosx10.15 + macosx11.1 DTXcode - 1201 + 1240 DTXcodeBuild - 12A7300 + 12D4e LSMinimumSystemVersion 10.13 NSHumanReadableCopyright diff --git a/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS/AppleEventIntegration b/Editor/Plugins/AppleEventIntegration.bundle/Contents/MacOS/AppleEventIntegration index 2b35f07b31468458eee5d89d32c97737eb05cf82..3ffd3e000723a2935b00e2a4e7ad7a2c141a9047 100644 GIT binary patch delta 8251 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 diff --git a/Editor/ProjectGeneration/ProjectGeneration.cs b/Editor/ProjectGeneration/ProjectGeneration.cs index 2e61e10..7a12909 100644 --- a/Editor/ProjectGeneration/ProjectGeneration.cs +++ b/Editor/ProjectGeneration/ProjectGeneration.cs @@ -148,7 +148,7 @@ namespace Microsoft.Unity.VisualStudio.Editor private void RefreshCurrentInstallation() { var editor = CodeEditor.CurrentEditor as VisualStudioEditor; - editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, out m_CurrentInstallation); + editor?.TryGetVisualStudioInstallationForPath(CodeEditor.CurrentEditorInstallation, searchInstallations: true, out m_CurrentInstallation); } public void Sync() @@ -370,7 +370,7 @@ namespace Microsoft.Unity.VisualStudio.Editor { return TypeCache .GetTypesDerivedFrom() - .Where(t => t.Assembly.GetName().Name != "SyntaxTree.VisualStudio.Unity.Bridge") // never call into the bridge if loaded with the package + .Where(t => t.Assembly.GetName().Name != KnownAssemblies.Bridge) // never call into the bridge if loaded with the package .Select(t => t.GetMethod(name, SR.BindingFlags.Public | SR.BindingFlags.NonPublic | SR.BindingFlags.Static)) .Where(m => m != null); } diff --git a/Editor/VisualStudioEditor.cs b/Editor/VisualStudioEditor.cs index 3ba37cf..60f5410 100644 --- a/Editor/VisualStudioEditor.cs +++ b/Editor/VisualStudioEditor.cs @@ -7,11 +7,11 @@ using System; using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using UnityEditor; using UnityEngine; using Unity.CodeEditor; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Unity.VisualStudio.EditorTests")] [assembly: InternalsVisibleTo("Unity.VisualStudio.Standalone.EditorTests")] @@ -22,42 +22,44 @@ namespace Microsoft.Unity.VisualStudio.Editor [InitializeOnLoad] public class VisualStudioEditor : IExternalCodeEditor { - private static readonly IVisualStudioInstallation[] _installations; - internal static bool IsOSX => Application.platform == RuntimePlatform.OSXEditor; internal static bool IsWindows => !IsOSX && Path.DirectorySeparatorChar == FileUtility.WinSeparator && Environment.NewLine == "\r\n"; - CodeEditor.Installation[] IExternalCodeEditor.Installations => _installations + CodeEditor.Installation[] IExternalCodeEditor.Installations => _discoverInstallations.Result .Select(i => i.ToCodeEditorInstallation()) .ToArray(); + private static readonly AsyncOperation _discoverInstallations; + private readonly IGenerator _generator = new ProjectGeneration(); static VisualStudioEditor() + { + if (IsWindows) + Discovery.FindVSWhere(); + + CodeEditor.Register(new VisualStudioEditor()); + + _discoverInstallations = AsyncOperation.Run(DiscoverInstallations); + } + + private static IVisualStudioInstallation[] DiscoverInstallations() { try { - _installations = Discovery + return Discovery .GetVisualStudioInstallations() .ToArray(); } catch (Exception ex) { UnityEngine.Debug.LogError($"Error detecting Visual Studio installations: {ex}"); - _installations = Array.Empty(); - } - - CodeEditor.Register(new VisualStudioEditor()); - } - - internal static bool IsEnabled - { - get - { - return CodeEditor.CurrentEditor is VisualStudioEditor; + return Array.Empty(); } } + internal static bool IsEnabled => CodeEditor.CurrentEditor is VisualStudioEditor; + public void CreateIfDoesntExist() { if (!_generator.HasSolutionBeenGenerated()) @@ -68,16 +70,19 @@ namespace Microsoft.Unity.VisualStudio.Editor { } - internal virtual bool TryGetVisualStudioInstallationForPath(string editorPath, out IVisualStudioInstallation installation) + internal virtual bool TryGetVisualStudioInstallationForPath(string editorPath, bool searchInstallations, out IVisualStudioInstallation installation) { - // lookup for well known installations - foreach (var candidate in _installations) + if (searchInstallations) { - if (!string.Equals(Path.GetFullPath(editorPath), Path.GetFullPath(candidate.Path), StringComparison.OrdinalIgnoreCase)) - continue; + // lookup for well known installations + foreach (var candidate in _discoverInstallations.Result) + { + if (!string.Equals(Path.GetFullPath(editorPath), Path.GetFullPath(candidate.Path), StringComparison.OrdinalIgnoreCase)) + continue; - installation = candidate; - return true; + installation = candidate; + return true; + } } return Discovery.TryDiscoverInstallation(editorPath, out installation); @@ -85,7 +90,7 @@ namespace Microsoft.Unity.VisualStudio.Editor public virtual bool TryGetInstallationForPath(string editorPath, out CodeEditor.Installation installation) { - var result = TryGetVisualStudioInstallationForPath(editorPath, out var vsi); + var result = TryGetVisualStudioInstallationForPath(editorPath, searchInstallations: false, out var vsi); installation = vsi == null ? default : vsi.ToCodeEditorInstallation(); return result; } diff --git a/Editor/VisualStudioIntegration.cs b/Editor/VisualStudioIntegration.cs index 08616ab..50fbaf5 100644 --- a/Editor/VisualStudioIntegration.cs +++ b/Editor/VisualStudioIntegration.cs @@ -11,6 +11,8 @@ using System.Net.Sockets; using Microsoft.Unity.VisualStudio.Editor.Messaging; using Microsoft.Unity.VisualStudio.Editor.Testing; using UnityEditor; +using UnityEditor.PackageManager; +using UnityEditor.PackageManager.Requests; using UnityEngine; using MessageType = Microsoft.Unity.VisualStudio.Editor.Messaging.MessageType; @@ -32,11 +34,15 @@ namespace Microsoft.Unity.VisualStudio.Editor private static readonly object _incomingLock = new object(); private static readonly object _clientsLock = new object(); + private static ListRequest _listRequest; + static VisualStudioIntegration() { if (!VisualStudioEditor.IsEnabled) return; + _listRequest = UnityEditor.PackageManager.Client.List(); + RunOnceOnUpdate(() => { // Despite using ReuseAddress|!ExclusiveAddressUse, we can fail here: @@ -59,6 +65,35 @@ namespace Microsoft.Unity.VisualStudio.Editor }); EditorApplication.update += OnUpdate; + + CheckLegacyAssemblies(); + } + + private static void CheckLegacyAssemblies() + { + var checkList = new HashSet(new[] { KnownAssemblies.UnityVS, KnownAssemblies.Messaging, KnownAssemblies.Bridge }); + + try + { + var assemblies = AppDomain + .CurrentDomain + .GetAssemblies() + .Where(a => checkList.Contains(a.GetName().Name)); + + foreach (var assembly in assemblies) + { + // for now we only want to warn against local assemblies, do not check externals. + var relativePath = FileUtility.MakeRelativeToProjectPath(assembly.Location); + if (relativePath == null) + continue; + + Debug.LogWarning($"Project contains legacy assembly that could interfere with the Visual Studio Package. You should delete {relativePath}"); + } + } + catch (Exception) + { + // abandon legacy check + } } private static void RunOnceOnUpdate(Action action) @@ -98,8 +133,33 @@ namespace Microsoft.Unity.VisualStudio.Editor OnMessage(args.Message); } + private static void HandleListRequestCompletion() + { + const string packageName = "com.unity.ide.visualstudio"; + + if (_listRequest.Status == StatusCode.Success) + { + var package = _listRequest.Result.FirstOrDefault(p => p.name == packageName); + + if (package != null + && Version.TryParse(package.version, out var packageVersion) + && Version.TryParse(package.versions.latest, out var latestVersion) + && packageVersion < latestVersion) + { + Debug.LogWarning($"Visual Studio Editor Package version {package.versions.latest} is available, we strongly encourage you to update from the Unity Package Manager for a better Visual Studio integration"); + } + } + + _listRequest = null; + } + private static void OnUpdate() { + if (_listRequest != null && _listRequest.IsCompleted) + { + HandleListRequestCompletion(); + } + lock (_incomingLock) { while (_incoming.Count > 0) diff --git a/package.json b/package.json index db7b9b9..60df51b 100644 --- a/package.json +++ b/package.json @@ -2,21 +2,21 @@ "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.8", + "version": "2.0.9", "unity": "2019.4", "unityRelease": "21f1", "dependencies": { "com.unity.test-framework": "1.1.9" }, "relatedPackages": { - "com.unity.ide.visualstudio.tests": "2.0.8" + "com.unity.ide.visualstudio.tests": "2.0.9" }, "upmCi": { - "footprint": "c51cc3db630d4f769464e8f12c2154af3ca5242c" + "footprint": "b1cf463b7fca9fa8a65053f6120bce69640f5cea" }, "repository": { "url": "https://github.cds.internal.unity3d.com/unity/com.unity.ide.visualstudio.git", "type": "git", - "revision": "5cdf5d932e6ecbbd83bbe6a40eec2a94b4979501" + "revision": "c7cd4c6319806423b3d918b3e9599244e3993d41" } }