| |
| |
| |
| |
| |
| using System; |
| using System.IO; |
| using System.Collections.Generic; |
| using System.Diagnostics; |
| using System.Text.RegularExpressions; |
| using System.Linq; |
| using UnityEngine; |
|
|
| namespace Microsoft.Unity.VisualStudio.Editor |
| { |
| internal static class Discovery |
| { |
| internal const string ManagedWorkload = "Microsoft.VisualStudio.Workload.ManagedGame"; |
|
|
| internal static string _vsWherePath; |
|
|
| public static void FindVSWhere() |
| { |
| _vsWherePath = FileUtility.GetPackageAssetFullPath("Editor", "VSWhere", "vswhere.exe"); |
| } |
|
|
| public static IEnumerable<IVisualStudioInstallation> GetVisualStudioInstallations() |
| { |
| if (VisualStudioEditor.IsWindows) |
| { |
| foreach (var installation in QueryVsWhere()) |
| yield return installation; |
| } |
|
|
| if (VisualStudioEditor.IsOSX) |
| { |
| var candidates = Directory.EnumerateDirectories("/Applications", "*.app"); |
| foreach (var candidate in candidates) |
| { |
| if (TryDiscoverInstallation(candidate, out var installation)) |
| yield return installation; |
| } |
| } |
| } |
|
|
| private static bool IsCandidateForDiscovery(string path) |
| { |
| if (File.Exists(path) && VisualStudioEditor.IsWindows && Regex.IsMatch(path, "devenv.exe$", RegexOptions.IgnoreCase)) |
| return true; |
|
|
| if (Directory.Exists(path) && VisualStudioEditor.IsOSX && Regex.IsMatch(path, "Visual\\s?Studio(?!.*Code.*).*.app$", RegexOptions.IgnoreCase)) |
| return true; |
|
|
| return false; |
| } |
|
|
| public static bool TryDiscoverInstallation(string editorPath, out IVisualStudioInstallation installation) |
| { |
| installation = null; |
|
|
| if (string.IsNullOrEmpty(editorPath)) |
| return false; |
|
|
| if (!IsCandidateForDiscovery(editorPath)) |
| return false; |
|
|
| |
| var fvi = editorPath; |
|
|
| |
| if (VisualStudioEditor.IsOSX) |
| { |
| fvi = Path.Combine(editorPath, "Contents/Resources/lib/monodevelop/bin/VisualStudio.exe"); |
|
|
| if (!File.Exists(fvi)) |
| fvi = Path.Combine(editorPath, "Contents/MonoBundle/VisualStudio.exe"); |
|
|
| if (!File.Exists(fvi)) |
| fvi = Path.Combine(editorPath, "Contents/MonoBundle/VisualStudio.dll"); |
| } |
|
|
| if (!File.Exists(fvi)) |
| return false; |
|
|
| |
| |
| var vi = FileVersionInfo.GetVersionInfo(fvi); |
| var version = new Version(vi.ProductVersion); |
| var isPrerelease = vi.IsPreRelease || string.Concat(editorPath, "/" + vi.FileDescription).ToLower().Contains("preview"); |
|
|
| installation = new VisualStudioInstallation() |
| { |
| IsPrerelease = isPrerelease, |
| Name = $"{vi.FileDescription}{(isPrerelease && VisualStudioEditor.IsOSX ? " Preview" : string.Empty)} [{version.ToString(3)}]", |
| Path = editorPath, |
| Version = version |
| }; |
| return true; |
| } |
|
|
| #region VsWhere Json Schema |
| #pragma warning disable CS0649 |
| [Serializable] |
| internal class VsWhereResult |
| { |
| public VsWhereEntry[] entries; |
|
|
| public static VsWhereResult FromJson(string json) |
| { |
| return JsonUtility.FromJson<VsWhereResult>("{ \"" + nameof(VsWhereResult.entries) + "\": " + json + " }"); |
| } |
|
|
| public IEnumerable<VisualStudioInstallation> ToVisualStudioInstallations() |
| { |
| foreach (var entry in entries) |
| { |
| yield return new VisualStudioInstallation() |
| { |
| Name = $"{entry.displayName} [{entry.catalog.productDisplayVersion}]", |
| Path = entry.productPath, |
| IsPrerelease = entry.isPrerelease, |
| Version = Version.Parse(entry.catalog.buildVersion) |
| }; |
| } |
| } |
| } |
|
|
| [Serializable] |
| internal class VsWhereEntry |
| { |
| public string displayName; |
| public bool isPrerelease; |
| public string productPath; |
| public VsWhereCatalog catalog; |
| } |
|
|
| [Serializable] |
| internal class VsWhereCatalog |
| { |
| public string productDisplayVersion; |
| public string buildVersion; |
| } |
| #pragma warning restore CS3021 |
| #endregion |
|
|
| private static IEnumerable<VisualStudioInstallation> QueryVsWhere() |
| { |
| var progpath = _vsWherePath; |
|
|
| if (string.IsNullOrWhiteSpace(progpath)) |
| return Enumerable.Empty<VisualStudioInstallation>(); |
|
|
| var result = ProcessRunner.StartAndWaitForExit(progpath, "-prerelease -format json -utf8"); |
|
|
| if (!result.Success) |
| throw new Exception($"Failure while running vswhere: {result.Error}"); |
|
|
| |
| return VsWhereResult |
| .FromJson(result.Output) |
| .ToVisualStudioInstallations(); |
| } |
| } |
| } |
|
|