/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Extension/CompilerPackage.cs
184 строки
8 KB
Julien Couvreur
Warn for multiple blank lines in source (#65451)
17 ноя 2022, 22:55
Не верифицирован
17 ноя 2022, 22:55
a8824e8
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using EnvDTE; using Microsoft; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Task = System.Threading.Tasks.Task; namespace Roslyn.Compilers.Extension { [Guid("31C0675E-87A4-4061-A0DD-A4E510FCCF97")] public sealed class CompilerPackage : AsyncPackage { public static string RoslynHive = null; protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress) { await base.InitializeAsync(cancellationToken, progress).ConfigureAwait(true); await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var reg = (ILocalRegistry2)await GetServiceAsync(typeof(SLocalRegistry)).ConfigureAwait(true); cancellationToken.ThrowIfCancellationRequested(); Assumes.Present(reg); var packagePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string localRegistryRoot; reg.GetLocalRegistryRoot(out localRegistryRoot); var registryParts = localRegistryRoot.Split('\\'); // Is it a valid Hive looks similar to: // 'Software\Microsoft\VisualStudio\14.0' 'Software\Microsoft\VisualStudio\14.0Roslyn' 'Software\Microsoft\VSWinExpress\14.0' if (registryParts.Length >= 4) { var skuName = registryParts[2]; var hiveName = registryParts[3]; RoslynHive = string.Format(@"{0}.{1}", registryParts[2], registryParts[3]); await WriteMSBuildFilesAsync(packagePath, RoslynHive, cancellationToken).ConfigureAwait(true); try { Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection.DisableMarkDirty = true; Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection.SetGlobalProperty("RoslynHive", RoslynHive); } finally { Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection.DisableMarkDirty = false; } } } private async Task WriteMSBuildFilesAsync(string packagePath, string hiveName, CancellationToken cancellationToken) { // A map of the file name to the content we need to ensure exists in the file var filesToWrite = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); // The props we want to be included as early as possible since we want our tasks to be used and // to ensure our setting of targets path happens early enough filesToWrite.Add(await GetMSBuildRelativePathAsync($@"Imports\Microsoft.Common.props\ImportBefore\Roslyn.Compilers.Extension.{hiveName}.props", cancellationToken).ConfigureAwait(true), $@"<?xml version=""1.0"" encoding=""utf-8""?> <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> <PropertyGroup Condition=""'$(RoslynHive)' == '{hiveName}'""> <CSharpCoreTargetsPath>{packagePath}\Microsoft.CSharp.Core.targets</CSharpCoreTargetsPath> <VisualBasicCoreTargetsPath>{packagePath}\Microsoft.VisualBasic.Core.targets</VisualBasicCoreTargetsPath> </PropertyGroup> <UsingTask TaskName=""Microsoft.CodeAnalysis.BuildTasks.Csc"" AssemblyFile=""{packagePath}\Microsoft.Build.Tasks.CodeAnalysis.dll"" Condition=""'$(RoslynHive)' == '{hiveName}'"" /> <UsingTask TaskName=""Microsoft.CodeAnalysis.BuildTasks.Vbc"" AssemblyFile=""{packagePath}\Microsoft.Build.Tasks.CodeAnalysis.dll"" Condition=""'$(RoslynHive)' == '{hiveName}'"" /> </Project>"); // This targets content we want to be included later since the project file might touch UseSharedCompilation var targetsContent = $@"<?xml version=""1.0"" encoding=""utf-8""?> <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> <!-- If we're not using the compiler server, set ToolPath/Exe to direct to the exes in this package --> <PropertyGroup Condition=""'$(RoslynHive)' == '{hiveName}' and '$(UseSharedCompilation)' == 'false'""> <CscToolPath>{packagePath}</CscToolPath> <CscToolExe>csc.exe</CscToolExe> <VbcToolPath>{packagePath}</VbcToolPath> <VbcToolExe>vbc.exe</VbcToolExe> </PropertyGroup> </Project>"; filesToWrite.Add(await GetMSBuildRelativePathAsync($@"Microsoft.CSharp.targets\ImportBefore\Roslyn.Compilers.Extension.{hiveName}.targets", cancellationToken).ConfigureAwait(true), targetsContent); filesToWrite.Add(await GetMSBuildRelativePathAsync($@"Microsoft.VisualBasic.targets\ImportBefore\Roslyn.Compilers.Extension.{hiveName}.targets", cancellationToken).ConfigureAwait(true), targetsContent); // First we want to ensure any Roslyn files with our hive name that we aren't writing -- this is probably // leftovers from older extensions var msbuildDirectory = new DirectoryInfo(await GetMSBuildPathAsync(cancellationToken).ConfigureAwait(true)); if (msbuildDirectory.Exists) { foreach (var file in msbuildDirectory.EnumerateFiles($"*Roslyn*{hiveName}*", SearchOption.AllDirectories)) { if (!filesToWrite.ContainsKey(file.FullName)) { file.Delete(); } } } try { foreach (var fileAndContents in filesToWrite) { var parentDirectory = new DirectoryInfo(Path.GetDirectoryName(fileAndContents.Key)); parentDirectory.Create(); // If we already know the file has the same contents, then we can skip if (File.Exists(fileAndContents.Key) && File.ReadAllText(fileAndContents.Key) == fileAndContents.Value) { continue; } File.WriteAllText(fileAndContents.Key, fileAndContents.Value); } } catch (Exception e) { var msg = $@"{e.Message} To reload the Roslyn compiler package, close Visual Studio and any MSBuild processes, then restart Visual Studio."; VsShellUtilities.ShowMessageBox( this, msg, null, OLEMSGICON.OLEMSGICON_WARNING, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } private async Task<string> GetMSBuildVersionStringAsync(CancellationToken cancellationToken) { await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); var dte = (DTE)await GetServiceAsync(typeof(SDTE)).ConfigureAwait(true); var parts = dte.Version.Split('.'); if (parts.Length != 2) { throw new Exception($"Unrecognized Visual Studio Version: {dte.Version}"); } int majorVersion = int.Parse(parts[0]); if (majorVersion >= 16) { // Starting in Visual Studio 2019, the folder is just called "Current". See // https://github.com/Microsoft/msbuild/issues/4149 for further commentary. return "Current"; } else { return majorVersion + ".0"; } } private async Task<string> GetMSBuildPathAsync(CancellationToken cancellationToken) { var version = await GetMSBuildVersionStringAsync(cancellationToken).ConfigureAwait(true); var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); return Path.Combine(localAppData, $@"Microsoft\MSBuild\{version}"); } private async Task<string> GetMSBuildRelativePathAsync(string relativePath, CancellationToken cancellationToken) { return Path.Combine(await GetMSBuildPathAsync(cancellationToken).ConfigureAwait(true), relativePath); } } }