diff --git a/.gitignore b/.gitignore index b27c388..4f9bb98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ [Oo]bj/ [Bb]in/ +.binaries/ TestResults/ _ReSharper.*/ /packages/ @@ -12,4 +13,7 @@ PublishProfiles/ .vs .build/ .testPublish/ -msbuild.* \ No newline at end of file +msbuild.* +src/packages/**/pp/ +src/packages/**/*.pp/ +src/**/tools/Roslyn*/ \ No newline at end of file diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config index ab19453..e47923b 100644 --- a/.nuget/NuGet.Config +++ b/.nuget/NuGet.Config @@ -4,10 +4,7 @@ - + + - - - - \ No newline at end of file diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe index be85ec2..212f26c 100644 Binary files a/.nuget/NuGet.exe and b/.nuget/NuGet.exe differ diff --git a/Build.cmd b/Build.cmd index 3a51a27..0b7d720 100644 --- a/Build.cmd +++ b/Build.cmd @@ -1,21 +1,21 @@ @ECHO OFF setlocal - set EnableNuGetPackageRestore=true -set logOptions=/flp:Summary;Verbosity=normal;LogFile=msbuild.log /flp1:warningsonly;logfile=msbuild.wrn /flp2:errorsonly;logfile=msbuild.err +set MSBUILDEXE=msbuild.exe + +set cfgOption=/p:Configuration=Release +REM set cfgOption=/p:Configuration=Debug +REM set cfgOption=/p:Configuration=Debug;Release +if not "%1"=="" set cfgOption=/p:Configuration= + +set logOptions=/v:n /flp:Summary;Verbosity=diag;LogFile=msbuild.log /flp1:warningsonly;logfile=msbuild.wrn /flp2:errorsonly;logfile=msbuild.err +REM set logOptions=/v:diag /flp:Summary;Verbosity=normal;LogFile=msbuild.log /flp1:warningsonly;logfile=msbuild.wrn /flp2:errorsonly;logfile=msbuild.err -REM Find the most recent 32bit MSBuild.exe on the system. Require v12.0 (installed with VS2013) or later since .NET 4.0 -REM is not supported. Always quote the %MSBuild% value when setting the variable and never quote %MSBuild% references. -set MSBuild="%ProgramFiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe" -if not exist %MSBuild% @set MSBuild="%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe" -if not exist %MSBuild% ( - echo Could not find msbuild.exe. Please run this from a Visual Studio developer prompt - goto BuildFail -) +echo Please build from VS 2015(or newer version) Developer Command Prompt -%MSBuild% "%~dp0\RoslynCodeProvider.msbuild" %logOptions% /v:minimal /maxcpucount /nodeReuse:false %* +%MSBUILDEXE% "%~dp0\RoslynCodeProvider.msbuild" /t:Build %logOptions% /maxcpucount /nodeReuse:false %cfgOption%%* if %ERRORLEVEL% neq 0 goto BuildFail goto BuildSuccess diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md new file mode 100644 index 0000000..775f221 --- /dev/null +++ b/CODE-OF-CONDUCT.md @@ -0,0 +1,6 @@ +# Code of Conduct + +This project has adopted the code of conduct defined by the Contributor Covenant +to clarify expected behavior in our community. + +For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). diff --git a/Clean.cmd b/Clean.cmd new file mode 100644 index 0000000..c4a2c41 --- /dev/null +++ b/Clean.cmd @@ -0,0 +1,37 @@ +@ECHO OFF + +setlocal + +set MSBUILDEXE=msbuild.exe + +set cfgOption=/p:Configuration=Release +REM set cfgOption=/p:Configuration=Debug +REM set cfgOption=/p:Configuration=Debug;Release +if not "%1"=="" set cfgOption=/p:Configuration= + +set logOptions=/v:n /flp:Summary;Verbosity=diag;LogFile=msbuild.log /flp1:warningsonly;logfile=msbuild.wrn /flp2:errorsonly;logfile=msbuild.err +REM set logOptions=/v:diag /flp:Summary;Verbosity=diag;LogFile=msbuild.log /flp1:warningsonly;logfile=msbuild.wrn /flp2:errorsonly;logfile=msbuild.err + +%MSBUILDEXE% "%~dp0\RoslynCodeProvider.msbuild" /t:Clean %logOptions% /maxcpucount /nodeReuse:false %cfgOption%%* + +pushd %~dp0\src\RoslynCodeProviderTest +rd /q /s bin +rd /q /s obj +popd +pushd %~dp0\src\DotNetCompilerPlatformTasks +rd /q /s bin +rd /q /s obj +popd +pushd %~dp0\src\Packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform +rd /q /s tools +rd /q /s tasks +rd /q /s build\pp +popd +pushd %~dp0\src\Packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites +rd /q /s tools\pp +popd +rd /q /s bin +rd /q /s obj +del /F msbuild.* + +endlocal \ No newline at end of file diff --git a/README.md b/README.md index 8c51bcf..2c0e154 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,176 @@ -### Microsoft.CodeDom.Providers.DotNetCompilerPlatform - +## Introduction Replacement CodeDOM providers that use the new .NET Compiler Platform ("Roslyn") compiler as a service APIs. This provides support for new language features in systems using CodeDOM (e.g. ASP.NET runtime compilation) as well as improving the compilation performance of these systems. Please see the blog [Enabling the .NET Compiler Platform (“Roslyn”) in ASP.NET applications](https://blogs.msdn.microsoft.com/webdev/2014/05/12/enabling-the-net-compiler-platform-roslyn-in-asp-net-applications/) for an introduction to Microsoft.CodeDom.Providers.DotNetCompilerPlatform. ## Updates -*[Announcing the DotNetCompilerPlatform 1.0.2 release](https://blogs.msdn.microsoft.com/webdev/2016/09/20/announcing-the-dotnetcompilerplatform-1-0-2-release/) + ++ #### Version 4.5.0 + - #### Refreshed compilers + In keeping with the new versioning scheme for this project, the version has been revved to 4.5 to match the version of the compilers included. + + :information_source: The source of compiler tools in this package has been updated to [Microsoft.Net.Compilers.**Toolset**](https://www.nuget.org/packages/Microsoft.Net.Compilers.Toolset) from the old, deprecated `Microsoft.Net.Compilers` package that had been used before. There shouldn't be any behavioral change due to this change in Roslyn packages. + + - #### Fixed targets-based tool copy + The msbuild targets-based identification and copy of Roslyn files to the project output was not working correctly in the last version. This has been fixed to ensure that Roslyn compiler files are copied to the correct location during build. + + - #### Still .Net >= 4.7.2 + This change was made with the introduction of the 4.X series of this package. But is worth mentioning here, as the call-out of that change is now hidden in the collapsed section below. + +
+Older Updates + ++ #### Version 4.1.0 + - #### :warning: Drop install.ps1, Rely more on msbuild :warning: + Nuget has moved on from install.ps1. We had one foot in the msbuild camp before, and one foot still in the install.ps1 camp. Time to just jump in with both feet. See the 'RoslynRegisterInConfig' setting description below. + + **Moving fully to an msbuild/targets-based model will break project-less ASP.Net "Web Sites."** The old install.ps1 way of doing things was becoming less tenable as NuGet continued to evolve. The switch to msbuild/targets was an easy choice. But "Web Site" projects have very limited support in msbuild. We have created a new package that brings back the 'install.ps1' functionality of the 3.X releases _only for WebSites._ It is called [Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites](https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites). + + - #### Refreshed current compilers + In keeping with the new versioning scheme for this project, the version has been revved to 4.1 to match the version of the compilers included. + + - #### No more old compilers + Stop carrying old versions of compilers. If you upgrade to get new compilers, you get new compilers. The old compilers that might carry references to binaries that get flagged in security scans even though the binaries don't get copied to the ouput directory... they just won't be included in the package anymore. + + - #### .Net >= 4.7.2 + As a result of not keeping older compilers packaged in this project, we can no longer support versions before 4.7.2 because compiler versions 3.0 and newer only support 4.7.2+. + ++ #### Version 3.11.1 + - #### Fixed targets-based tool copy + The msbuild targets-based identification and copy of Roslyn files to the project output was not working correctly in the last version. This has been fixed to ensure that Roslyn compiler files are copied to the correct location during build. + ++ #### Version 3.11.0 + - #### Refreshed compilers + In keeping with the new versioning scheme for this project, the version has been revved to 3.11 to match the version of the compilers included. + + - #### Only support .Net >= 4.6.2 + Older versions of .Net are out of support, so this update also removes support for them and no longer carries the oldest version of the compiler tools that was used in previous versions. + + - #### Non-web apps and 'aspnet:RoslynCompilerLocation' + The appSetting `aspnet:RoslynCompilerLocation` can still be used to point at a specific download of the Roslyn compiler tools, but this package is hopefully a little more forgiving when searching for a default location and should accomodate both web projects as well as non-web projects without requiring this setting. + ++ #### Version 3.6.1 + - #### Fixed targets-based tool copy + The msbuild targets-based identification and copy of Roslyn files to the project output was not working correctly in the last version. This has been fixed to ensure that Roslyn compiler files are copied to the correct location during build. + ++ #### Version 3.6.0 + - #### Refreshed compilers (and versioning) + This is most likely the update everyone has been looking for. This package contains updated Roslyn bits for newer target frameworks. If your project is targeting 4.7.2 or above, this package will use `Microsoft.Net.Compilers` version 3.5 with your build. You might notice that we have revved our package version to match the most recent compiler version included. For target frameworks 4.6 through 4.7.1, the 2.10 version of compilers is used. (A slight update from 2.9 that shipped with our last package.) And as before, projects targeting 4.5.* will get version 1.3.2 of the compilers. (Note that the language version for 4.6 and above is set to "default", which means C# 7.3 max for full framework projects.) + + - #### Config restoration + In the past, when updating or re-installing this package after re-targeting your project - the nuget package would overwrite your config entries for the codedom provider with the default options again. Borrowing a feature from Microsoft.Configuration.ConfigurationBuilders, the 3.5 packages now temporarily store existing config when uninstalling and attempt to restore it when installing instead of blindly writing defaults again. Unfortunately this won't help the 2.0* ==> 3.5 update scenario since 2.0* doesn't save configuration to the temp file. But future updates or retargeting from 3.5 will hopefully blow less custom configuration out of the water. + + - #### ProviderOptions for compilers + Configuration options for these codedom providers has been a little haphazard in the past. Some things are set through environment variables, and some through appSettings. All such options apply to all codedom providers configured. This package still respects the old ways of setting those various config options, but also allows many of them to be set on individual codedom providers using the [providerOption](https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/compiler/provideroption-element) collection in the config file. See the [Configurations](#Configurations) section below to see what options exist. + + - #### Turning off ASP.Net "magic" + When this project was first started, it was intended as an extension for full-framework ASP.Net only. As such, it took the liberty of "massaging" some of the compiler options it was given before starting the compiler, and there was no way to prevent the modifications from happening. If the codedom providers in this package are created using the default constructor as ASP.Net uses, we still do the magic for compat reasons. If your code is calling directly into codedom providers from this package and passing compiler options in to the constructor, then the magic is turned off. This feature can be explicitly enabled or disabled using a new provider option. See the (Configurations)[#Configurations] section below for details. + + - #### dotnet buildable + For the adventurous developer who likes to use `dotnet` to build their full-framework projects for whatever reason, some of the MSBuild tasks our package was creating were not compatible with that environment. This package update comes with custom MSBuild tasks that should work in both the `dotnet` and full MSBuild/VS environments. + ++ #### Version 2.0.0 + - #### There is a **breaking change**? + Before 2.0.0 version, Microsoft.CodeDom.Providers.DotNetCompilerPlatform nupkg references Microsoft.Net.Compilers nupkg in order to deploy the Roslyn compiler assemblies unto you application folder. In version 2.0.0 version, the dependency is removed. Instead, Microsoft.CodeDom.Providers.DotNetCompilerPlatform nupkg includes all the Roslyn compiler assemblies under tools folder. + + - #### What does that mean? + When you build your project in Visual Studio, Visual Studio(msbuild) will use the Roslyn compiler shipped with it to compile the source code in your project. However, if Microsoft.Net.Compilers nupkg is installed in your project, it overrides the compiler location and Visual Studio(msbuild) will use the Roslyn compiler from Microsoft.Net.Compilers nupkg. This causes two problems. 1. When you install the latest Visual Studio update which always contains new Roslyn Compiler and you configure Visual Studio to use latest language feature. And you do use the latest language feature in your code, the intellisense works and IDE doesn't show any syntax error. However, when you build your project, you see some compilation error. This is because your project is still using the old version of Microsoft.Net.Compilers nupkg. 2. The Roslyn compiler shipped with Visual Studio is NGen'd which means it has better cold startup performance. So it takes more time to build the project, if the project references Microsoft.Net.Compilers nupkg. + + - #### What shall I do? + If you are using Visual Studio 2017 with latest update, you should upgrade Microsoft.CodeDom.Providers.DotNetCompilerPlatform nupkg to 2.0.0 and **remove Microsoft.Net.Compilers nupkg from your project**. +
+ +## Configurations +Generally, command-line options for the codedom compilers can be specified using the `compilerOptions` attribute of the compiler when it is registered in configuration. There are however, a handful of options for controlling some behaviors of this package that are not command-line options. These options fall into two broad categories and can be set as follows: + +### Build-time Options ++ #### Setting: RoslynToolPath + + **(V2) Specify the path to copy Roslyn compiler at build time** - When building projects, target files included by the Microsoft.CodeDom.Providers.DotNetCompilerPlatform nupkg will copy appropriate Roslyn compiler into bin\roslyn folder. With this setting, you can specify a custom path from which the build process will copy the Roslyn compiler, rather than using one of the pre-packaged Roslyn compilers. + + **How to use it** - ```msbuild mysolution.sln /t:build /p:RoslynToolPath="[Roslyn compiler folder full path]"``` + + **Use case** - In 2.0.0 version, Microsoft.CodeDom.Providers.DotNetCompilerPlatform nupkg removes the dependency on Microsoft.Net.Compilers nupkg. Instead, it embeds one version of Roslyn compiler inside the nupkg. It's possible that the embeded version of Roslyn compiler is not the one you want, so through this setting you can specify a version of Roslyn compiler at build time which will be copied to bin\roslyn folder. + ++ #### Setting: RoslynCopyToOutDir + + **(V4) Skip copying Roslyn compiler at build time** - When building projects, target files will copy the appropriate binaries specified by the 'RoslynToolPath' setting described above and copy them into the project output for runtime use. This copy step can be skipped by using this project setting. + + **How to use it** - ```msbuild mysolution.sln /t:build /p:RoslynCopyToOutDir="[true|false]"``` + ++ #### Setting: RoslynRegisterInConfig + + **(V4) Don't modify config at build time** - CodeDom providers are not magically picked up from referenced assemblies. They must be explicitly registered in config in order to be used. Prior to the Version 4 update, all modifications to config were performed via powershell scripts included in the nuget package. This powershell method worked with 'packages.config' apps, but does not work with 'PackageReference' apps. As more applications move towards the preferred 'PackageReference' way of doing things, we have updated our method of config registration to be an msbuild task instead of a powershell install script. We take care not to stomp over existing settings. But this step gets checked/performed on every build now instead of just on package install. Use this setting to skip the config update. + + **How to use it** - ```msbuild mysolution.sln /t:build /p:RoslynRegisterInConfig="[true|false]"``` + + **Use case** - This config-manipulation step happens on ever build. (Even designer builds.) We take care to be as non-invasive as possible, but if you want us to stay entirely hands-off and update your config registrations manually, this setting enables that. + +### Run-time Options + ++ #### Roslyn Compiler Location + + **Specify the path to load Roslyn compiler at runtime** - When asp.net compiles the views at runtime or precompile time(using aspnet_compiler to precompile the web app), Microsoft.CodeDom.Providers.DotNetCompilerPlatform needs a path to load Roslyn compiler. This setting can be used to specify this loading path. + + 1. **Environment variable** - This is the first setting Microsoft.CodeDom.Providers.DotNetCompilerPlatform reads. If this setting is used, Microsoft.CodeDom.Providers.DotNetCompilerPlatform will ignore the other setting. + + **Setting name** - ROSLYN_COMPILER_LOCATION + + **How to use it** - ```setx ROSLYN_COMPILER_LOCATION [Roslyn compiler folder full path]``` + + **Use case** - This is a machine wide setting. If you want to control the Roslyn compiler version used on your machine or you don't want a copy of Roslyn compiler under every application, then you can use this setting. + + 2. **AppSetting in config file** - This is the second option to specify the location of Roslyn compiler and it's only valid if the environment variable setting is not used. + + **Setting name** - aspnet:RoslynCompilerLocation + + **How to use it** - Add this appSetting into your config file ``` ``` + + **Use case** - This is a application level setting. If you have multiple projects in a solution and you want to use Microsoft.CodeDom.Providers.DotNetCompilerPlatform in several projects but you only want to install Microsoft.CodeDom.Providers.DotNetCompilerPlatform nupkg on one project. See [issue #25](https://github.com/aspnet/RoslynCodeDomProvider/issues/25). + + 3. **Provider Option** - This is the third option to specify the location of the Roslyn compiler bits, and it's only valid if the previous two options are not used. + + **Setting name** - `` + + **How to use it** - Add this providerOption into your config file under the `system.codedom/compilers/compiler` to which you want it to apply. + + **Use case** - This is a provider level setting. If you want to use different roslyn deployments for the codedom providers registered for different languages. + + 4. **Default setting** - The default location is bin\roslyn folder. + ++ #### Roslyn Server TTL + + **Specify the TTL of Roslyn compiler server** - Microsoft.CodeDom.Providers.DotNetCompilerPlatform leverages Roslyn compiler server(VBCSCompiler.exe) to compile the generated code. In order to save system resources, VBCSCompiler.exe will be shutdown after idling 10 seconds in the server environment. However, in the development environment(running your web application from visual studio) the idle time is set to 15 mininutes. The reason behind this is to improve the startup performance of your web application when you run/debug the application in Visual Studio, since VBCSCompiler.exe takes several seconds to start if relevant Roslyn assemblies are not NGen'd. With this setting, you can control the idle time of VBCSCompiler.exe. + + 1. **Environment variable** - This is the first setting Microsoft.CodeDom.Providers.DotNetCompilerPlatform reads. If this setting is used, Microsoft.CodeDom.Providers.DotNetCompilerPlatform will ignore the other setting. + + **Setting name** - VBCSCOMPILER_TTL + + **How to use it** - ```setx VBCSCOMPILER_TTL [num of seconds]``` + + **Use case** - When you develop your web application in Visual Studio, you don't modify and run your application very frequently. In this scenario, you may use this setting to shorten the idle time of VBCSCompiler.exe and let the process end earlier which can release some system resources. + + 2. **Provider Option** - This is the second option to specify how long the Roslyn compiler server should stay alive, and it's only valid if the previous option is not used. + + **Setting name** - `` + + **How to use it** - Add this providerOption into your config file under the `system.codedom/compilers/compiler` to which you want it to apply. + ++ #### ASP.Net "Magic" + + **Disable ASP.Net "Magic"** - If the helpful manipulation of `compilerOptions` for running smoothly in an ASP.Net environment is not so helpful for your environment, you can disable this and Microsoft.CodeDom.Providers.DotNetCompilerPlatform will get out of your way, using the `compilerOptions` provided to it with no additions or manipulations. + + **Provider Option** - This is the only option to specify whether `compilerOptions` manipulation should happen automatically or not. + + **Setting name** - `` + + **How to use it** - Add this providerOption into your config file under the `system.codedom/compilers/compiler` to which you want it to apply. + ++ #### Warnings as Errors + + **Treat Warnings as Errors** - This `System.CodeDom.Compiler.CompilerParameters` property is unfortunately at a conflict with ability to tell the compiler how to behave directly with a `compilerOption`. Prior to v3.5, Microsoft.CodeDom.Providers.DotNetCompilerPlatform would always set this to false. Now developers have a choice in how to manage this conflict. + + **Provider Option** - `` - The default is false. + + **How to use it** - Add this providerOption into your config file under the `system.codedom/compilers/compiler` to which you want it to apply. diff --git a/RoslynCodeProvider.msbuild b/RoslynCodeProvider.msbuild index 9d80ea0..45a8a5b 100644 --- a/RoslynCodeProvider.msbuild +++ b/RoslynCodeProvider.msbuild @@ -1,24 +1,25 @@ - - - + + + - + - + + - - + + @@ -27,10 +28,18 @@ + + + + + + + + @@ -49,5 +58,8 @@ - + + + + diff --git a/RoslynCodeProvider.sln b/RoslynCodeProvider.sln index 2ab268f..519a24b 100644 --- a/RoslynCodeProvider.sln +++ b/RoslynCodeProvider.sln @@ -1,24 +1,32 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32126.317 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{566A9F52-15C9-4BD0-AD3A-9CC7D391834E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{770A45B7-BC65-4FC4-94FF-7F99838F3219}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest", "RoslynCodeProviderTest\Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest.csproj", "{12B521BD-F065-4F81-BD7A-D6F715B38F12}" + ProjectSection(ProjectDependencies) = postProject + {7EC5863F-7FF1-41C7-A384-8FFF81531E7A} = {7EC5863F-7FF1-41C7-A384-8FFF81531E7A} + {E3D81E13-7489-4064-B789-AE1B02C7C616} = {E3D81E13-7489-4064-B789-AE1B02C7C616} + EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CodeDom.Providers.DotNetCompilerPlatform", "src\Microsoft.CodeDom.Providers.DotNetCompilerPlatform\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.csproj", "{BE52ED6A-F180-499D-80BB-B0237B50023C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetCompilerPlatform", "src\DotNetCompilerPlatform\DotNetCompilerPlatform.csproj", "{BE52ED6A-F180-499D-80BB-B0237B50023C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Packages", "src\Packages\Packages.csproj", "{7EC5863F-7FF1-41C7-A384-8FFF81531E7A}" ProjectSection(ProjectDependencies) = postProject {BE52ED6A-F180-499D-80BB-B0237B50023C} = {BE52ED6A-F180-499D-80BB-B0237B50023C} + {E3D81E13-7489-4064-B789-AE1B02C7C616} = {E3D81E13-7489-4064-B789-AE1B02C7C616} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{793EB7E3-C526-48B6-9614-7AA972D9BB46}" ProjectSection(SolutionItems) = preProject + azure-pipeline\azure-pipeline.yml = azure-pipeline\azure-pipeline.yml + README.md = README.md packages\repositories.config = packages\repositories.config + tools\RoslynCodeProvider.Extensions.targets = tools\RoslynCodeProvider.Extensions.targets RoslynCodeProvider.msbuild = RoslynCodeProvider.msbuild tools\RoslynCodeProvider.settings.targets = tools\RoslynCodeProvider.settings.targets EndProjectSection @@ -30,6 +38,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6EB4E0 .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetCompilerPlatformTasks", "src\DotNetCompilerPlatformTasks\DotNetCompilerPlatformTasks.csproj", "{E3D81E13-7489-4064-B789-AE1B02C7C616}" + ProjectSection(ProjectDependencies) = postProject + {BE52ED6A-F180-499D-80BB-B0237B50023C} = {BE52ED6A-F180-499D-80BB-B0237B50023C} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -48,6 +61,10 @@ Global {7EC5863F-7FF1-41C7-A384-8FFF81531E7A}.Debug|Any CPU.Build.0 = Debug|Any CPU {7EC5863F-7FF1-41C7-A384-8FFF81531E7A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7EC5863F-7FF1-41C7-A384-8FFF81531E7A}.Release|Any CPU.Build.0 = Release|Any CPU + {E3D81E13-7489-4064-B789-AE1B02C7C616}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3D81E13-7489-4064-B789-AE1B02C7C616}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E3D81E13-7489-4064-B789-AE1B02C7C616}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E3D81E13-7489-4064-B789-AE1B02C7C616}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -56,5 +73,9 @@ Global {12B521BD-F065-4F81-BD7A-D6F715B38F12} = {770A45B7-BC65-4FC4-94FF-7F99838F3219} {BE52ED6A-F180-499D-80BB-B0237B50023C} = {566A9F52-15C9-4BD0-AD3A-9CC7D391834E} {7EC5863F-7FF1-41C7-A384-8FFF81531E7A} = {566A9F52-15C9-4BD0-AD3A-9CC7D391834E} + {E3D81E13-7489-4064-B789-AE1B02C7C616} = {566A9F52-15C9-4BD0-AD3A-9CC7D391834E} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A5B8F404-C4DF-48B5-80FE-6FC256ADCEC3} EndGlobalSection EndGlobal diff --git a/RoslynCodeProviderTest/App.config b/RoslynCodeProviderTest/App.config new file mode 100644 index 0000000..82edf08 --- /dev/null +++ b/RoslynCodeProviderTest/App.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RoslynCodeProviderTest/CSharpProviderTest.cs b/RoslynCodeProviderTest/CSharpProviderTest.cs index 6fe9361..68b10ac 100644 --- a/RoslynCodeProviderTest/CSharpProviderTest.cs +++ b/RoslynCodeProviderTest/CSharpProviderTest.cs @@ -1,36 +1,39 @@ -using Microsoft.CodeDom.Providers.DotNetCompilerPlatform; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; +using System; using System.CodeDom.Compiler; -using System.IO; +using Microsoft.CodeDom.Providers.DotNetCompilerPlatform; +using Xunit; namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest { - [TestClass] public class CSharpProviderTest { private CommonCodeDomProviderTests commonTests = new CommonCodeDomProviderTests(); private static CodeDomProvider csharpCodeProvider; - [ClassInitialize] - public static void ClassInitialize(TestContext testContext) { - string frameworkFolder = Path.GetDirectoryName(typeof(object).Assembly.Location); - string compilerPath = Path.Combine(frameworkFolder, "csc.exe"); - var codeDomProviderType = typeof(Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider); + static CSharpProviderTest() { +#pragma warning disable CS0618 csharpCodeProvider = new CSharpCodeProvider(compilerSettings: CompilerSettingsHelper.CSC); +#pragma warning restore CS0618 + AppContext.SetSwitch("Switch.System.DisableTempFileCollectionDirectoryFeature", true); } - [TestMethod] + [Fact] + public void AssemblyVersion() + { + commonTests.AssemblyVersion(csharpCodeProvider); + } + + [Fact] public void FileExtension() { commonTests.FileExtension(csharpCodeProvider, "cs"); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_Parse_Error() { commonTests.CompileAssemblyFromSource_Parse_Error(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_WarningAsError() { commonTests.CompileAssemblyFromSource_WarningAsError(csharpCodeProvider, // the variable a is declared but not used @@ -38,80 +41,97 @@ public void CompileAssemblyFromSource_WarningAsError() { "CS0168"/*errorNumber*/); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_ReferenceAssembly_AssemblyNameOnly() { commonTests.CompileAssemblyFromSource_ReferenceAssembly_AssemblyNameOnly(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_ReferenceAssembly_NameCannotBeResolved() { commonTests.CompileAssemblyFromSource_ReferenceAssembly_NameCannotBeResolved(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_ReferenceAssembly_LocalReference() { commonTests.CompileAssemblyFromSource_ReferenceAssembly_LocalReference(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_ReferenceAssembly_PathWithComma() { commonTests.CompileAssemblyFromSource_ReferenceAssembly_PathWithComma(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_GenerateInMemory_True() { commonTests.CompileAssemblyFromSource_GenerateInMemory_True(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_GenerateInMemory_False() { commonTests.CompileAssemblyFromSource_GenerateInMemory_False(csharpCodeProvider, "public class FooClass { public string Execute() { return \"output\";}}"); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_InvalidOutputPath() { commonTests.CompileAssemblyFromSource_InvalidOutputPath(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_GenerateExecutable_True() { commonTests.CompileAssemblyFromSource_GenerateExecutable_True(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_GenerateExecutable_True_Failed() { commonTests.CompileAssemblyFromSource_GenerateExecutable_True_Failed(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_CreateOutputFileFailed() { commonTests.CompileAssemblyFromSource_CreateOutputFileFailed(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_CreatePDBFileFailed() { commonTests.CompileAssemblyFromSource_CreatePDBFileFailed(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_IncludeDebugInformation_True() { commonTests.CompileAssemblyFromSource_IncludeDebugInformation_True(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_IncludeDebugInformation_False() { commonTests.CompileAssemblyFromSource_IncludeDebugInformation_False(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromDom() { commonTests.CompileAssemblyFromDom(csharpCodeProvider); } - [TestMethod] + [Fact] public void CompileAssemblyFromFile() { commonTests.CompileAssemblyFromFile(csharpCodeProvider); } + + [Fact] + public void CompileAssemblyFromFile_ASPNet_Magic() + { + // Complete added frippery is: "/nowarn:1659;1699;1701;612;618" + ProviderOptions opts = new ProviderOptions(CompilerSettingsHelper.CSC) { UseAspNetSettings = true }; + commonTests.CompileAssemblyFromFile_CheckArgs(new CSharpCodeProvider(opts), "/nowarn:1659;1699;1701;612;618", true); + } + + [Fact] + public void CompileAssemblyFromFile_No_ASPNet_Magic() + { + // _codeProvider uses options (aka CompilerSettingsHelper.VB) created via constructor, so it should + // have the ASP.Net frippery disabled. + commonTests.CompileAssemblyFromFile_CheckArgs(csharpCodeProvider, "/nowarn:1659;1699;1701;612;618", false); + } + } } diff --git a/RoslynCodeProviderTest/CommonCodeDomProviderTests.cs b/RoslynCodeProviderTest/CommonCodeDomProviderTests.cs index 6a46c2c..6a161f7 100644 --- a/RoslynCodeProviderTest/CommonCodeDomProviderTests.cs +++ b/RoslynCodeProviderTest/CommonCodeDomProviderTests.cs @@ -5,17 +5,30 @@ using System.IO; using System.Reflection; using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Xunit; namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest { - [TestClass] - public class CommonCodeDomProviderTests { + + public class CommonCodeDomProviderTests + { + public static readonly Version ExpectedVersion = new Version(4, 5, 0, 0); // Maj, Min, Build, Rev + public static readonly string ExpectedNugetVersion = "4.5.0-preview1"; private const int Failed = 1; private const int Success = 0; + public void AssemblyVersion(CodeDomProvider provider) + { + var ver = provider.GetType().Assembly.GetName().Version; + + Assert.Equal(ExpectedVersion.Major, ver.Major); + Assert.Equal(ExpectedVersion.Minor, ver.Minor); + Assert.Equal(ExpectedVersion.Build, ver.Build); + } + public void FileExtension(CodeDomProvider provider, string extension) { - Assert.AreEqual(extension, provider.FileExtension); + Assert.Equal(extension, provider.FileExtension); } @@ -26,10 +39,10 @@ public void CompileAssemblyFromSource_Parse_Error(CodeDomProvider provider) { "public class FooClass { public string Execute() { return \"output\" /*;*/ }}" ); - Assert.AreEqual(Failed, result.NativeCompilerReturnValue); - Assert.IsTrue(result.Errors.HasErrors); - Assert.AreEqual(1, result.Errors.Count); - Assert.AreEqual("CS1002", result.Errors[0].ErrorNumber); + Assert.Equal(Failed, result.NativeCompilerReturnValue); + Assert.True(result.Errors.HasErrors); + Assert.Single(result.Errors); + Assert.Equal("CS1002", result.Errors[0].ErrorNumber); } @@ -44,9 +57,9 @@ public void CompileAssemblyFromSource_WarningAsError(CodeDomProvider provider, s sourceCode ); - Assert.AreEqual(Failed, result.NativeCompilerReturnValue); - Assert.IsTrue(result.Errors.HasErrors); - Assert.AreEqual(errorNumber, result.Errors[0].ErrorNumber); + Assert.Equal(Failed, result.NativeCompilerReturnValue); + Assert.True(result.Errors.HasErrors); + Assert.Equal(errorNumber, result.Errors[0].ErrorNumber); } @@ -60,12 +73,12 @@ public void CompileAssemblyFromSource_ReferenceAssembly_AssemblyNameOnly(CodeDom "public class FooClass { public string Execute() { return \"output\"; }}" ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); + Assert.Equal(Success, result.NativeCompilerReturnValue); var type = result.CompiledAssembly.GetType("FooClass"); var obj = Activator.CreateInstance(type); var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); - Assert.IsNull(result.PathToAssembly); - Assert.AreEqual(@"output", output); + Assert.Null(result.PathToAssembly); + Assert.Equal(@"output", output); } @@ -81,8 +94,8 @@ public void CompileAssemblyFromSource_ReferenceAssembly_NameCannotBeResolved(Cod "public class FooClass { public string Execute() { int a; return \"output\"; }}" ); - // Assert.IsNull(result.PathToAssembly); - Assert.AreEqual(Failed, result.NativeCompilerReturnValue); + // Assert.Null(result.PathToAssembly); + Assert.Equal(Failed, result.NativeCompilerReturnValue); bool referenceErrorInOutput = false; foreach (var line in result.Output) { @@ -91,7 +104,7 @@ public void CompileAssemblyFromSource_ReferenceAssembly_NameCannotBeResolved(Cod } } - Assert.IsTrue(referenceErrorInOutput); + Assert.True(referenceErrorInOutput); } @@ -105,10 +118,10 @@ public void CompileAssemblyFromSource_ReferenceAssembly_LocalReference(CodeDomPr "public class FooClass1 { public static string Execute() { return \"output\";}}" ); - Assert.AreEqual(Success, result1.NativeCompilerReturnValue); - Assert.IsNotNull(result1.PathToAssembly); + Assert.Equal(Success, result1.NativeCompilerReturnValue); + Assert.NotNull(result1.PathToAssembly); tempFiles.Add(result1.PathToAssembly); - Assert.AreEqual(".dll", Path.GetExtension(result1.PathToAssembly)); + Assert.Equal(".dll", Path.GetExtension(result1.PathToAssembly)); string referenceName = Path.GetFileName(result1.PathToAssembly); var asm1 = GetAssemblyByName(result1.PathToAssembly); @@ -116,7 +129,7 @@ public void CompileAssemblyFromSource_ReferenceAssembly_LocalReference(CodeDomPr var obj1 = Activator.CreateInstance(type1); var output1 = type1.GetMethod("Execute").Invoke(obj1, new object[] { }); - Assert.AreEqual(@"output", output1); + Assert.Equal(@"output", output1); var param2 = new CompilerParameters(new string[] { referenceName }); param2.GenerateExecutable = true; @@ -124,9 +137,9 @@ public void CompileAssemblyFromSource_ReferenceAssembly_LocalReference(CodeDomPr param2, "public class FooClass2 { public static void Main() { System.Console.Write(FooClass1.Execute());}}" ); - Assert.IsNotNull(result2.PathToAssembly); + Assert.NotNull(result2.PathToAssembly); tempFiles.Add(result2.PathToAssembly); - Assert.AreEqual(Success, result2.NativeCompilerReturnValue); + Assert.Equal(Success, result2.NativeCompilerReturnValue); AppDomain newAppDomain = null; try { newAppDomain = System.AppDomain.CreateDomain("NewApplicationDomain"); @@ -157,17 +170,17 @@ public void CompileAssemblyFromSource_ReferenceAssembly_PathWithComma(CodeDomPro "public class FooClass1 { public static string Execute() { return \"output\";}}" ); - Assert.AreEqual(Success, result1.NativeCompilerReturnValue); - Assert.IsNotNull(result1.PathToAssembly); + Assert.Equal(Success, result1.NativeCompilerReturnValue); + Assert.NotNull(result1.PathToAssembly); tempFiles.Add(result1.PathToAssembly); - Assert.AreEqual(".dll", Path.GetExtension(result1.PathToAssembly)); + Assert.Equal(".dll", Path.GetExtension(result1.PathToAssembly)); string referenceName = Path.GetFileName(result1.PathToAssembly); var asm1 = GetAssemblyByName(result1.PathToAssembly); var type1 = asm1.GetType("FooClass1"); var obj1 = Activator.CreateInstance(type1); var output1 = type1.GetMethod("Execute").Invoke(obj1, new object[] { }); - Assert.AreEqual(@"output", output1); + Assert.Equal(@"output", output1); var param2 = new CompilerParameters(new string[] { referenceName }); param2.GenerateExecutable = true; @@ -176,8 +189,8 @@ public void CompileAssemblyFromSource_ReferenceAssembly_PathWithComma(CodeDomPro "public class FooClass2 { public static void Main() { System.Console.Write(FooClass1.Execute());}}" ); - Assert.AreEqual(Success, result2.NativeCompilerReturnValue); - Assert.IsNotNull(result2.PathToAssembly); + Assert.Equal(Success, result2.NativeCompilerReturnValue); + Assert.NotNull(result2.PathToAssembly); tempFiles.Add(result2.PathToAssembly); AppDomain newAppDomain = null; try { @@ -204,12 +217,12 @@ public void CompileAssemblyFromSource_GenerateInMemory_True(CodeDomProvider prov "using System.Runtime; public class FooClass { public string Execute() { return \"output\";}}" ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); + Assert.Equal(Success, result.NativeCompilerReturnValue); var type = result.CompiledAssembly.GetType("FooClass"); var obj = Activator.CreateInstance(type); var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); - Assert.IsNull(result.PathToAssembly); - Assert.AreEqual(@"output", output); + Assert.Null(result.PathToAssembly); + Assert.Equal(@"output", output); } public void CompileAssemblyFromSource_GenerateInMemory_False(CodeDomProvider provider, string sourceCode) { @@ -224,8 +237,8 @@ public void CompileAssemblyFromSource_GenerateInMemory_False(CodeDomProvider pro sourceCode ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); - Assert.IsNotNull(result.PathToAssembly); + Assert.Equal(Success, result.NativeCompilerReturnValue); + Assert.NotNull(result.PathToAssembly); // Read assembly into memory: Assembly asm = GetAssemblyByName(result.PathToAssembly); @@ -234,10 +247,10 @@ public void CompileAssemblyFromSource_GenerateInMemory_False(CodeDomProvider pro var obj = Activator.CreateInstance(type); var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); - Assert.AreEqual(@"output", output); - Assert.AreEqual(param.OutputAssembly, result.PathToAssembly); + Assert.Equal(@"output", output); + Assert.Equal(param.OutputAssembly, result.PathToAssembly); - Assert.IsTrue(File.Exists(param.OutputAssembly)); + Assert.True(File.Exists(param.OutputAssembly)); } finally { DeleteFiles(tempFiles); @@ -257,8 +270,8 @@ public void CompileAssemblyFromSource_InvalidOutputPath(CodeDomProvider provider "public class FooClass { public string Execute() { return \"output\";}}" ); - // Assert.IsNull(result.PathToAssembly); - Assert.AreEqual(Failed, result.NativeCompilerReturnValue); + // Assert.Null(result.PathToAssembly); + Assert.Equal(Failed, result.NativeCompilerReturnValue); } finally { DeleteFiles(tempFiles); @@ -280,8 +293,8 @@ public void CompileAssemblyFromSource_GenerateExecutable_True(CodeDomProvider pr "public class FooClass { public static void Main(){} public string Execute() { return \"output\";}}" ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); - Assert.IsNotNull(result.PathToAssembly); + Assert.Equal(Success, result.NativeCompilerReturnValue); + Assert.NotNull(result.PathToAssembly); tempFiles.Add(result.PathToAssembly); Assembly asm = GetAssemblyByName(result.PathToAssembly); @@ -289,8 +302,8 @@ public void CompileAssemblyFromSource_GenerateExecutable_True(CodeDomProvider pr var obj = Activator.CreateInstance(type); var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); - Assert.AreEqual(".exe", Path.GetExtension(result.PathToAssembly)); - Assert.AreEqual(@"output", output); + Assert.Equal(".exe", Path.GetExtension(result.PathToAssembly)); + Assert.Equal(@"output", output); } finally { DeleteFiles(tempFiles); @@ -312,9 +325,9 @@ public void CompileAssemblyFromSource_GenerateExecutable_True_Failed(CodeDomProv "public class FooClass {public string Execute() { return \"output\";}}" ); - Assert.AreEqual(Failed, result.NativeCompilerReturnValue); - // Assert.IsNull(result.PathToAssembly); - Assert.AreEqual("CS5001"/*miss main entry*/, result.Errors[0].ErrorNumber); + Assert.Equal(Failed, result.NativeCompilerReturnValue); + // Assert.Null(result.PathToAssembly); + Assert.Equal("CS5001"/*miss main entry*/, result.Errors[0].ErrorNumber); } @@ -331,10 +344,10 @@ public void CompileAssemblyFromSource_CreateOutputFileFailed(CodeDomProvider pro "public class FooClass { public string Execute() { return \"output\";}}" ); - Assert.AreEqual(Failed, result.NativeCompilerReturnValue); + Assert.Equal(Failed, result.NativeCompilerReturnValue); // The InProc provider does not give error while the old provider // does. We probably should fix the behavior of InProc provider. - // Assert.IsFalse(result.Errors.HasErrors); + // Assert.False(result.Errors.HasErrors); bool filenameInOutput = false; foreach (var line in result.Output) { if (line.Contains(Path.GetFileName(param.OutputAssembly))) { @@ -342,7 +355,7 @@ public void CompileAssemblyFromSource_CreateOutputFileFailed(CodeDomProvider pro } } - Assert.IsTrue(filenameInOutput); + Assert.True(filenameInOutput); } } finally { @@ -367,10 +380,10 @@ public void CompileAssemblyFromSource_CreatePDBFileFailed(CodeDomProvider provid "public class FooClass { public string Execute() { return \"output\";}}" ); - Assert.AreEqual(Failed, result.NativeCompilerReturnValue); + Assert.Equal(Failed, result.NativeCompilerReturnValue); // The InProc provider does not give error while the old provider // does. We probably should fix the behavior of InProc provider. - // Assert.IsFalse(result.Errors.HasErrors); + // Assert.False(result.Errors.HasErrors); bool filenameInOutput = false; foreach (var line in result.Output) { if (line.Contains(Path.GetFileName(pdbFilename))) { @@ -378,7 +391,7 @@ public void CompileAssemblyFromSource_CreatePDBFileFailed(CodeDomProvider provid } } - Assert.IsTrue(filenameInOutput); + Assert.True(filenameInOutput); } } finally { @@ -402,11 +415,11 @@ public void CompileAssemblyFromSource_IncludeDebugInformation_True(CodeDomProvid "public class FooClass { public string Execute() { return \"output\";}}" ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); + Assert.Equal(Success, result.NativeCompilerReturnValue); // In Debug mode, visual studio would try to load the pdb file. // Delete the file before it's held by VS. - Assert.IsTrue(File.Exists(pdbFileName)); + Assert.True(File.Exists(pdbFileName)); File.Delete(pdbFileName); // Read assembly into memory: @@ -415,9 +428,9 @@ public void CompileAssemblyFromSource_IncludeDebugInformation_True(CodeDomProvid var obj = Activator.CreateInstance(type); var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); - Assert.AreEqual(@"output", output); - Assert.AreEqual(param.OutputAssembly, result.PathToAssembly); - Assert.IsTrue(File.Exists(param.OutputAssembly)); + Assert.Equal(@"output", output); + Assert.Equal(param.OutputAssembly, result.PathToAssembly); + Assert.True(File.Exists(param.OutputAssembly)); } finally { DeleteFiles(tempFiles); @@ -440,7 +453,7 @@ public void CompileAssemblyFromSource_IncludeDebugInformation_False(CodeDomProvi "public class FooClass { public string Execute() { return \"output\";}}" ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); + Assert.Equal(Success, result.NativeCompilerReturnValue); // Read assembly into memory: Assembly asm = GetAssemblyByName(param.OutputAssembly); @@ -448,10 +461,10 @@ public void CompileAssemblyFromSource_IncludeDebugInformation_False(CodeDomProvi var obj = Activator.CreateInstance(type); var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); - Assert.AreEqual(@"output", output); - Assert.AreEqual(param.OutputAssembly, result.PathToAssembly); - Assert.IsTrue(File.Exists(param.OutputAssembly)); - Assert.IsFalse(File.Exists(pdbFileName)); + Assert.Equal(@"output", output); + Assert.Equal(param.OutputAssembly, result.PathToAssembly); + Assert.True(File.Exists(param.OutputAssembly)); + Assert.False(File.Exists(pdbFileName)); } finally { DeleteFiles(tempFiles); @@ -492,19 +505,27 @@ public void CompileAssemblyFromDom(CodeDomProvider provider) { compileUnit ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); + Assert.Equal(Success, result.NativeCompilerReturnValue); var type = result.CompiledAssembly.GetType(string.Format("{0}.{1}", spaceName, className)); var obj = Activator.CreateInstance(type); var output = type.GetMethod(methodName).Invoke(obj, new object[] { }); - Assert.AreEqual("output", output); + Assert.Equal("output", output); } - public void CompileAssemblyFromFile(CodeDomProvider provider) { + public void CompileAssemblyFromFile(CodeDomProvider provider) + { + CompileAssemblyFromFile_CheckArgs(provider, null, false); + } + + public void CompileAssemblyFromFile_CheckArgs(CodeDomProvider provider, string argStringToFind, bool expected) { var sourcePath = Path.Combine(Path.GetTempPath(), "foobarSourcefile.cs"); try { using (var sourceStream = File.Create(sourcePath)) { var content = "public class FooClass { public string Execute() { return \"output\";}}"; + // If we're checking cmd args, we actually want to fail compilation so we can examine output. + if (argStringToFind != null) + content = "nonsense that doesn't compile."; var bytes = Encoding.ASCII.GetBytes(content); sourceStream.Write(bytes, 0, bytes.Length); } @@ -516,11 +537,18 @@ public void CompileAssemblyFromFile(CodeDomProvider provider) { sourcePath ); - Assert.AreEqual(Success, result.NativeCompilerReturnValue); + if (argStringToFind != null) + { + Assert.NotEqual(Success, result.NativeCompilerReturnValue); + Assert.Equal(expected, result.Output[0].Contains(argStringToFind)); + return; + } + + Assert.Equal(Success, result.NativeCompilerReturnValue); var type = result.CompiledAssembly.GetType("FooClass"); var obj = Activator.CreateInstance(type); var output = type.GetMethod("Execute").Invoke(obj, new object[] { }); - Assert.AreEqual(@"output", output); + Assert.Equal(@"output", output); } finally { File.Delete(sourcePath); diff --git a/RoslynCodeProviderTest/CompilerSettingsHelper.cs b/RoslynCodeProviderTest/CompilerSettingsHelper.cs index 543a47b..85f57d1 100644 --- a/RoslynCodeProviderTest/CompilerSettingsHelper.cs +++ b/RoslynCodeProviderTest/CompilerSettingsHelper.cs @@ -7,12 +7,19 @@ using System.Threading.Tasks; namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest { + +#pragma warning disable CS0618 + internal class TestCompilerSettings : ICompilerSettings { + public string CompilerFullPath { get; set; } + public int CompilerServerTimeToLive { get; set; } + } + internal static class CompilerSettingsHelper { private const int DefaultCompilerServerTTL = 0; // set TTL to 0 to turn of keepalive switch - private static ICompilerSettings _csc = new CompilerSettings(CompilerFullPath(@"csc.exe"), DefaultCompilerServerTTL); - private static ICompilerSettings _vb = new CompilerSettings(CompilerFullPath(@"vbc.exe"), DefaultCompilerServerTTL); + private static ICompilerSettings _csc = new ProviderOptions(CompilerFullPath(@"csc.exe"), DefaultCompilerServerTTL); + private static ICompilerSettings _vb = new ProviderOptions(CompilerFullPath(@"vbc.exe"), DefaultCompilerServerTTL); public static ICompilerSettings CSC { get { @@ -33,4 +40,5 @@ private static string CompilerFullPath(string relativePath) { return compilerFullPath; } } +#pragma warning restore CS0618 } diff --git a/RoslynCodeProviderTest/Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest.csproj b/RoslynCodeProviderTest/Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest.csproj index 01e419d..2f13405 100644 --- a/RoslynCodeProviderTest/Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest.csproj +++ b/RoslynCodeProviderTest/Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest.csproj @@ -1,5 +1,6 @@  - + + Debug @@ -9,29 +10,29 @@ Properties Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest - v4.5 + v4.7.2 + 512 true + true $(RepositoryRoot)src\35MSSharedLib1024.snk {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 + 15.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages False UnitTest - SAK - SAK - SAK - SAK - $(TestOutputPath) ..\ true + + true full false + bin\Debug\ DEBUG;TRACE prompt 4 @@ -39,65 +40,54 @@ pdbonly true + bin\Release\ TRACE prompt 4 - - $(ReferencePackagesPath)Moq.4.2.1402.2112\lib\net40\Moq.dll - + + + - - - - - - - - - - - - + + - + {be52ed6a-f180-499d-80bb-b0237b50023c} - Microsoft.CodeDom.Providers.DotNetCompilerPlatform + DotNetCompilerPlatform + True + True - + + + + + 2.4.1 + + + 2.4.1 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + 2.4.3 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + - - - - - False - - - False - - - False - - - False - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. diff --git a/RoslynCodeProviderTest/PackageVerificationTests.cs b/RoslynCodeProviderTest/PackageVerificationTests.cs new file mode 100644 index 0000000..421490e --- /dev/null +++ b/RoslynCodeProviderTest/PackageVerificationTests.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using Xunit; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest +{ + /// + /// Holds ZipArchive objects for the two packages, so we only open them once. + /// + public class PackageVerificationFixture : IDisposable + { +#if DEBUG + private const string PackageOutDir = @"..\..\..\.binaries\Packages\Debug"; +#else + private const string PackageOutDir = @"..\..\..\.binaries\Packages\Release"; +#endif + + public ZipArchive CompilerPlatformZip { get; } + public ZipArchive WebSitesZip { get; } + + public PackageVerificationFixture() + { + string codedomProvider = Path.Combine(PackageOutDir, $"Microsoft.CodeDom.Providers.DotNetCompilerPlatform.{CommonCodeDomProviderTests.ExpectedNugetVersion}.nupkg"); + Assert.True(File.Exists(codedomProvider), $"File not found: {codedomProvider}"); + + string websites = Path.Combine(PackageOutDir, $"Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites.{CommonCodeDomProviderTests.ExpectedNugetVersion}.nupkg"); + Assert.True(File.Exists(websites), $"File not found: {websites}"); + + CompilerPlatformZip = ZipFile.OpenRead(codedomProvider); + WebSitesZip = ZipFile.OpenRead(websites); + } + + public void Dispose() + { + CompilerPlatformZip?.Dispose(); + WebSitesZip?.Dispose(); + } + } + + /// + /// A collection definition so that xUnit ties our fixture to this group of tests. + /// + [CollectionDefinition("PackageVerificationCollection")] + public class PackageVerificationCollection : ICollectionFixture { } + + [Collection("PackageVerificationCollection")] + public class PackageVerificationTests + { + private readonly PackageVerificationFixture _fixture; + + public PackageVerificationTests(PackageVerificationFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public void CompilerPlatformPackage_ContainsNet472TargetsFileAndNoForbiddenText() + { + var targetFiles = VerifyPlatforms(_fixture.CompilerPlatformZip, "build/", new[] { "net472" }, exclusive: true); + VerifyAllowedExtensions(targetFiles, new[] { ".targets" }); + Assert.Single(targetFiles); + + using (var reader = new StreamReader(targetFiles[0].Open())) + { + var content = reader.ReadToEnd(); + Assert.DoesNotContain("$compilerPlatformFQAN$", content, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("$roslynToolPath$", content, StringComparison.OrdinalIgnoreCase); + } + } + + [Fact] + public void WebSitesPlatformPackage_ContainsNet472Scripts() + { + var contentFiles = VerifyPlatforms(_fixture.WebSitesZip, "content/", new[] { "net472" }, exclusive: true); + VerifyAllowedExtensions(contentFiles, new[] { ".xdt" }); + Assert.Equal(2, contentFiles.Count); + + var scriptTools = _fixture.WebSitesZip.Entries + .Where(e => e.FullName.StartsWith("tools/", StringComparison.OrdinalIgnoreCase)) + .ToList(); + VerifyAllowedExtensions(scriptTools, new[] { ".ps1" }); + Assert.Equal(3, scriptTools.Count); + + foreach (var script in scriptTools) + { + using (var reader = new StreamReader(script.Open())) + { + var content = reader.ReadToEnd(); + Assert.DoesNotContain("$providerVersion$", content, StringComparison.OrdinalIgnoreCase); + } + } + } + + [Fact] + public void BothPackages_ContainDocsReadmeAndIconsDotnet() + { + VerifyCommonFiles(_fixture.CompilerPlatformZip); + VerifyCommonFiles(_fixture.WebSitesZip); + } + + [Fact] + public void CompilerPlatformPackage_ContainsRoslynDirectoryWithExpectedFiles() + { + var roslynDir = $"tools/Roslyn-{CommonCodeDomProviderTests.ExpectedVersion.Major}.{CommonCodeDomProviderTests.ExpectedVersion.Minor}.{CommonCodeDomProviderTests.ExpectedVersion.Revision}"; + var roslynDirEntries = _fixture.CompilerPlatformZip.Entries + .Where(e => e.FullName.StartsWith(roslynDir, StringComparison.OrdinalIgnoreCase)) + .ToList(); + Assert.True(roslynDirEntries.Count > 30, "Expected Roslyn directory with more than 30 files."); + + Assert.Contains(roslynDirEntries, e => e.Name.Equals("csc.exe", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(roslynDirEntries, e => e.Name.Equals("vbc.exe", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(roslynDirEntries, e => e.Name.Equals("VBCSCompiler.exe", StringComparison.OrdinalIgnoreCase)); + } + + [Fact] + public void PackageVersionsAndLibDllsMatch_IfPresent() + { + // Example placeholder test for future version checks + // Could parse .nuspec or compare with anything in /lib + // Implementation depends on specific project constraints + Assert.NotNull(_fixture.CompilerPlatformZip); + } + + private static void VerifyCommonFiles(ZipArchive zip) + { + Assert.Contains(zip.Entries, e => e.FullName.Equals("docs/Readme.md", StringComparison.OrdinalIgnoreCase)); + Assert.Contains(zip.Entries, e => e.FullName.Equals("icons/dotnet.png", StringComparison.OrdinalIgnoreCase)); + } + + private static IList VerifyPlatforms(ZipArchive zip, string dir, string[] platforms, bool exclusive = false, string extension = null) + { + dir = dir.TrimEnd('/') + "/"; + var filesInDir = zip.Entries + .Where(e => e.FullName.StartsWith(dir, StringComparison.OrdinalIgnoreCase)) + .Where(e => extension == null || e.FullName.EndsWith(extension, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + // Verify all platform directories exist + var platformDirs = platforms.Select(p => $"{dir}{p}/").ToList(); + foreach (var platformDir in platformDirs) + { + Assert.Contains(zip.Entries, e => e.FullName.StartsWith(platformDir, StringComparison.OrdinalIgnoreCase)); + } + + // Verify all files in the base directory are in an allowed platform folder + if (exclusive) + { + foreach (var entry in filesInDir) + { + var entryIsInAllowedPlatformFolder = platforms.Any(platform => entry.FullName.StartsWith($"{dir}{platform}/", StringComparison.OrdinalIgnoreCase)); + Assert.True(entryIsInAllowedPlatformFolder, $"Unexpected file: {entry.FullName}"); + } + } + + return filesInDir; + } + + private static void VerifyAllowedExtensions(IList entries, string[] allowedExtensions) + { + foreach (var entry in entries) + { + var extension = Path.GetExtension(entry.FullName); + Assert.Contains(allowedExtensions, ext => ext.Equals(extension, StringComparison.OrdinalIgnoreCase)); + } + } + } +} diff --git a/RoslynCodeProviderTest/ProviderOptionsTests.cs b/RoslynCodeProviderTest/ProviderOptionsTests.cs new file mode 100644 index 0000000..37990f1 --- /dev/null +++ b/RoslynCodeProviderTest/ProviderOptionsTests.cs @@ -0,0 +1,144 @@ +using System; +using System.Configuration; +using System.IO; +using Microsoft.CodeDom.Providers.DotNetCompilerPlatform; +using Xunit; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest +{ + public class ProviderOptionsTests { + + private static bool IsDev = false; + + static ProviderOptionsTests() { + if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("DEV_ENVIRONMENT")) || + !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("IN_DEBUG_MODE")) || + CompilationUtil.IsDebuggerAttached) + IsDev = true; + } + + [Fact] + public void DefaultSettings() + { + IProviderOptions opts = CompilationUtil.GetProviderOptionsFor(".fakevb"); + Assert.NotNull(opts); + Assert.Equal(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"roslyn"), opts.CompilerFullPath); // Would include csc.exe or vbc.exe if the extension we searched for wasn't fake. + Assert.Equal(IsDev ? 15 * 60 : 10, opts.CompilerServerTimeToLive); // 10 in Production. 900 in a "dev" environment. + Assert.True(opts.UseAspNetSettings); // Default is false... except through the GetProviderOptionsFor factory method we used here. + Assert.False(opts.WarnAsError); + Assert.Null(opts.CompilerVersion); + Assert.Equal(2, opts.AllOptions.Count); + Assert.Equal("foo2", opts.AllOptions["CustomSetting"]); + Assert.Equal("bar2", opts.AllOptions["AnotherCoolSetting"]); + } + + [Fact] + public void FromShortConstructor() + { + IProviderOptions opts = new ProviderOptions(@"D:\My\Fun\Compiler\Path\compiles.exe", 123); + Assert.NotNull(opts); + Assert.Equal(@"D:\My\Fun\Compiler\Path\compiles.exe", opts.CompilerFullPath); // Would include csc.exe or vbc.exe if the extension we searched for wasn't fake. + Assert.Equal(123, opts.CompilerServerTimeToLive); // 10 in Production. 900 in a "dev" environment. + Assert.False(opts.UseAspNetSettings); // Default via constructor is false. + Assert.False(opts.WarnAsError); + Assert.Null(opts.CompilerVersion); + Assert.Equal(0, opts.AllOptions.Count); + } + + [Fact] + public void FromICompilerSettings() + { +#pragma warning disable CS0618 + IProviderOptions opts = new ProviderOptions((ICompilerSettings)(CompilerSettingsHelper.CSC)); +#pragma warning restore CS0618 + Assert.NotNull(opts); + Assert.Equal(CompilerSettingsHelper.CSC.CompilerFullPath, opts.CompilerFullPath); // Would include csc.exe or vbc.exe if the extension we searched for wasn't fake. + Assert.Equal(CompilerSettingsHelper.CSC.CompilerServerTimeToLive, opts.CompilerServerTimeToLive); // 10 in Production. 900 in a "dev" environment. + Assert.False(opts.UseAspNetSettings); // Default via constructor is false. + Assert.False(opts.WarnAsError); + Assert.Null(opts.CompilerVersion); + Assert.Equal(0, opts.AllOptions.Count); + } + + // override defaults + [Fact] + public void FromProviderOptions() + { + IProviderOptions opts = CompilationUtil.GetProviderOptionsFor(".fakecs"); + Assert.NotNull(opts); + Assert.Equal(@"C:\Path\To\Nowhere\csc.exe", opts.CompilerFullPath); + Assert.Equal(42, opts.CompilerServerTimeToLive); + Assert.False(opts.UseAspNetSettings); + Assert.True(opts.WarnAsError); + Assert.Equal("v6.0", opts.CompilerVersion); + Assert.Equal(7, opts.AllOptions.Count); + Assert.Equal("foo", opts.AllOptions["CustomSetting"]); + Assert.Equal("bar", opts.AllOptions["AnotherCoolSetting"]); + } + + // override for location only + // Actually, we can't do this because A) AppSettings can be added but not cleaned up after this test, and + // B) the setting has probably already been read and cached by the AppSettings utility class, so updating + // the value here wouldn't have any affect anyway. + [Fact(Skip = "Need to fake config system first")] + public void FromAppSettings() + { + ConfigurationManager.AppSettings.Set("aspnet:RoslynCompilerLocation", @"C:\Location\for\all\from\appSettings\compiler.exe"); + IProviderOptions opts = CompilationUtil.GetProviderOptionsFor(".fakecs"); + ConfigurationManager.AppSettings.Remove("aspnet:RoslynCompilerLocation"); + + Assert.NotNull(opts); + Assert.Equal(@"C:\Location\for\all\from\appSettings\compiler.exe", opts.CompilerFullPath); + Assert.Equal(42, opts.CompilerServerTimeToLive); + Assert.False(opts.UseAspNetSettings); + Assert.True(opts.WarnAsError); + Assert.Equal("v6.0", opts.CompilerVersion); + Assert.Equal(7, opts.AllOptions.Count); + Assert.Equal("foo", opts.AllOptions["CustomSetting"]); + Assert.Equal("bar", opts.AllOptions["AnotherCoolSetting"]); + } + + // Environment overrides all for location and TTL + [Fact] + public void FromEnvironment() + { + // See note on the 'FromAppSettings' test. + //ConfigurationManager.AppSettings.Set("aspnet:RoslynCompilerLocation", @"C:\Location\for\all\from\appSettings\compiler.exe"); + Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", @"C:\My\Compiler\Location\vbcsc.exe"); + Environment.SetEnvironmentVariable("VBCSCOMPILER_TTL", "98"); + IProviderOptions opts = CompilationUtil.GetProviderOptionsFor(".fakecs"); + Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", null); + Environment.SetEnvironmentVariable("VBCSCOMPILER_TTL", null); + //ConfigurationManager.AppSettings.Remove("aspnet:RoslynCompilerLocation"); + + Assert.NotNull(opts); + Assert.Equal(@"C:\My\Compiler\Location\vbcsc.exe", opts.CompilerFullPath); + Assert.Equal(98, opts.CompilerServerTimeToLive); + Assert.False(opts.UseAspNetSettings); + Assert.True(opts.WarnAsError); + Assert.Equal("v6.0", opts.CompilerVersion); + Assert.Equal(7, opts.AllOptions.Count); + Assert.Equal("foo", opts.AllOptions["CustomSetting"]); + Assert.Equal("bar", opts.AllOptions["AnotherCoolSetting"]); + } + + // TTL must be int + [Fact] + public void TTL_MustBeInteger() + { + Environment.SetEnvironmentVariable("VBCSCOMPILER_TTL", "NotANumber"); + IProviderOptions opts = CompilationUtil.GetProviderOptionsFor(".fakevb"); + Environment.SetEnvironmentVariable("VBCSCOMPILER_TTL", null); + + Assert.NotNull(opts); + Assert.Equal(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"roslyn"), opts.CompilerFullPath); // Would include csc.exe or vbc.exe if the extension we searched for wasn't fake. + Assert.Equal(IsDev ? 15 * 60 : 10, opts.CompilerServerTimeToLive); // 10 in Production. 900 in a "dev" environment. + Assert.True(opts.UseAspNetSettings); // Default is false... except through the GetProviderOptionsFor factory method we used here. + Assert.False(opts.WarnAsError); + Assert.Null(opts.CompilerVersion); + Assert.Equal(2, opts.AllOptions.Count); + Assert.Equal("foo2", opts.AllOptions["CustomSetting"]); + Assert.Equal("bar2", opts.AllOptions["AnotherCoolSetting"]); + } + } +} diff --git a/RoslynCodeProviderTest/VBCodeProviderTests.cs b/RoslynCodeProviderTest/VBCodeProviderTests.cs index e3271f8..a170924 100644 --- a/RoslynCodeProviderTest/VBCodeProviderTests.cs +++ b/RoslynCodeProviderTest/VBCodeProviderTests.cs @@ -1,38 +1,36 @@ -using Microsoft.CodeDom.Providers.DotNetCompilerPlatform; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; +using System.CodeDom.Compiler; +using Microsoft.CodeDom.Providers.DotNetCompilerPlatform; +using Xunit; -namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest { - - - [TestClass] +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest +{ public class VBCodeProviderTests { private const int Failed = 1; private const int Success = 0; +#pragma warning disable CS0618 private CommonCodeDomProviderTests commonTests = new CommonCodeDomProviderTests(); private CodeDomProvider _codeProvider = new VBCodeProvider(CompilerSettingsHelper.VB); +#pragma warning restore CS0618 - [ClassInitialize] - public static void ClassInitialize(TestContext context) { - VBCompiler.MySupport = " "; + static VBCodeProviderTests() { + //VBCompiler.MySupport = " "; // Don't need to do this anymore with UseAspNetSettings feature VBCompiler.VBImportsString = " "; } - [TestMethod] + [Fact] + public void AssemblyVersion() + { + commonTests.AssemblyVersion(_codeProvider); + } + + [Fact] public void FileExtension() { commonTests.FileExtension(_codeProvider, "vb"); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_DLL_GenerateInMemory_False() { commonTests.CompileAssemblyFromSource_GenerateInMemory_False(_codeProvider, @"Public Class FooClass @@ -42,7 +40,7 @@ End Function End Class"); } - [TestMethod] + [Fact] public void CompileAssemblyFromSource_WarningAsError() { commonTests.CompileAssemblyFromSource_WarningAsError(_codeProvider, // the variable a is declared but not used @@ -54,6 +52,23 @@ End Function End Class", "BC42024"); } + + [Fact] + public void CompileAssemblyFromFile_ASPNet_Magic() + { + // Complete added frippery is: "/nowarn:41008,40000,40008 /define:_MYTYPE=\\\"Web\\\" /optionInfer+" + // But let's just check for _MYTYPE. + ProviderOptions opts = new ProviderOptions(CompilerSettingsHelper.VB) { UseAspNetSettings = true }; + commonTests.CompileAssemblyFromFile_CheckArgs(new VBCodeProvider(opts), "/define:_MYTYPE=\\\"Web\\\"", true); + } + + [Fact] + public void CompileAssemblyFromFile_No_ASPNet_Magic() + { + // _codeProvider uses options (aka CompilerSettingsHelper.VB) created via constructor, so it should + // have the ASP.Net frippery disabled. + commonTests.CompileAssemblyFromFile_CheckArgs(_codeProvider, "/define:_MYTYPE=\"Web\"", false); + } } } diff --git a/RoslynCodeProviderTest/packages.config b/RoslynCodeProviderTest/packages.config deleted file mode 100644 index ff7da7c..0000000 --- a/RoslynCodeProviderTest/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..8312d20 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,15 @@ +# Security Policy + +## Supported Versions + +The .NET Core and ASP.NET Core support policy, including supported versions can be found at the [.NET Core Support Policy Page](https://dotnet.microsoft.com/platform/support/policy/dotnet-core). + +## Reporting a Vulnerability + +Security issues and bugs should be reported privately to the Microsoft Security Response Center (MSRC), either by emailing secure@microsoft.com or via the portal at https://msrc.microsoft.com. +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your +original message. Further information, including the MSRC PGP key, can be found in the [MSRC Report an Issue FAQ](https://www.microsoft.com/en-us/msrc/faqs-report-an-issue). + +Reports via MSRC may qualify for the .NET Core Bug Bounty. Details of the .NET Core Bug Bounty including terms and conditions are at [https://aka.ms/corebounty](https://aka.ms/corebounty). + +Please do not open issues for anything you think might have a security implication. diff --git a/azure-pipeline/azure-pipeline.yml b/azure-pipeline/azure-pipeline.yml new file mode 100644 index 0000000..3633623 --- /dev/null +++ b/azure-pipeline/azure-pipeline.yml @@ -0,0 +1,146 @@ +# This Yaml Document has been converted by ESAI Yaml Pipeline Conversion Tool. +# Please make sure to check all the converted content, it is your team's responsibility to make sure that the pipeline is still valid and functions as expected. +# The SBOM tasks have been removed because they are not required for the unofficial template. +# You can manually enable SBOM in the unofficial template if needed, othewise its automatically enabled when using official template. https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/1es-pipeline-templates/features/sbom +# This pipeline will be extended to the MicroBuild template +# The Task 'PublishBuildArtifacts@1' has been converted to an output named 'Publish Artifact: Nuget packages' in the templateContext section. +trigger: none +schedules: +- cron: "0 0 14 * *" + branches: + include: + - main + always: true +resources: + repositories: + - repository: self + type: git + ref: refs/heads/main + - repository: MicroBuildTemplate + type: git + name: 1ESPipelineTemplates/MicroBuildTemplate + ref: refs/tags/release +name: $(Date:yyyyMMdd).$(Rev:r) +variables: + TeamName: AspNet + EnableNuGetPackageRestore: true +extends: + template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate + parameters: + sdl: + binskim: + enable: true + codeql: + enable: true + policheck: + enable: true + tsa: + enable: true + sourceAnalysisPool: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + os: windows + customBuildTags: + - ES365AIMigrationTooling + stages: + - stage: stage + jobs: + - job: Phase_1 + displayName: Phase 1 + timeoutInMinutes: 120 + cancelTimeoutInMinutes: 1 + pool: + name: VSEngSS-MicroBuild2022-1ES + templateContext: + mb: + signing: + enabled: true + signType: test + zipSources: false + outputs: + - output: pipelineArtifact + displayName: 'Publish Artifact: Nuget packages' + artifactName: Nuget packages + targetPath: $(Build.SourcesDirectory)\.binaries\Packages\Release + sbomEnabled: true + sbomBuildDropPath: $(Build.SourcesDirectory)\.binaries\Packages\Release + sbomBuildComponentPath: $(Build.SourcesDirectory)\.binaries\Packages\Release + sbomPackageName: Microsoft.AspNet.OutputCache + # sbomPackageVersion: $(NugetPackageVersion) + sbomValidate: true + steps: + - checkout: self + clean: true + fetchTags: true + persistCredentials: true + - task: NuGetToolInstaller@0 + displayName: Use NuGet 5.4.0 + inputs: + versionSpec: 5.4.0 + checkLatest: true + - task: NuGetCommand@2 + displayName: NuGet custom + inputs: + command: custom + arguments: install MicroBuild.Core -version 0.3.0 -OutputDirectory .\packages -source https://devdiv.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json + - task: NuGetCommand@2 + displayName: NuGet restore + inputs: + solution: RoslynCodeProvider.sln + - task: MSBuild@1 + displayName: Build solution RoslynCodeProvider.msbuild + inputs: + solution: RoslynCodeProvider.msbuild + msbuildVersion: 17.0 + msbuildArchitecture: x64 + configuration: Release + msbuildArguments: /p:GitCommit=$(Build.SourceVersion) /p:GitCommitLink="https://github.com/aspnet/RoslynCodeDomProvider/commit/$(Build.SourceVersion)" /p:SignType=real /p:SignAssembly=true /verbosity:normal + clean: true + createLogFile: true + logFileVerbosity: detailed + timeoutInMinutes: 120 + - task: CopyFiles@2 + displayName: Stage dll's for verification + inputs: + SourceFolder: $(Build.SourcesDirectory)\.binaries\bin\Release + Contents: | + DotNetCompilerPlatformTasks.dll + Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + System.Management.dll + TargetFolder: $(Build.SourcesDirectory)\.binaries\verify\dlls + CleanTargetFolder: true + OverWrite: true + - task: CopyFiles@2 + displayName: Stage nupkg's for verification + inputs: + SourceFolder: $(Build.SourcesDirectory)\.binaries\Packages\Release + Contents: | + *.nupkg + !*.symbols.nupkg + TargetFolder: $(Build.SourcesDirectory)\.binaries\verify\packages + CleanTargetFolder: true + OverWrite: true + - task: ms-vseng.MicroBuildShipTasks.7c429315-71ba-4cb3-94bb-f829c95f7915.MicroBuildCodesignVerify@1 + displayName: Verify Signed Binaries + inputs: + TargetFolders: $(Build.SourcesDirectory)\.binaries\verify\dlls + ExcludeFolders: .git MicroBuild apiscan + - task: ms-vseng.MicroBuildShipTasks.7c429315-71ba-4cb3-94bb-f829c95f7915.MicroBuildCodesignVerify@1 + displayName: Verify Signed Packages + inputs: + TargetFolders: $(Build.SourcesDirectory)\.binaries\verify\packages + WhiteListPathForCerts: $(Build.SourcesDirectory)\tools\.verif.whitelist + ExcludeFolders: .git MicroBuild decom *.xml + # Following article on https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/25351/APIScan-step-by-step-guide-to-setting-up-a-Pipeline + # No longer need the old format, and following guideline to use (ApiScanClientId) + - task: APIScan@2 + displayName: Run APIScan + inputs: + softwareFolder: '$(Build.SourcesDirectory)\.binaries\verify\dlls' + softwareName: 'Microsoft.CodeDom.Providers.DotNetCompilerPlatform' + softwareVersionNum: '*' + softwareBuildNum: '$(Build.BuildId)' + symbolsFolder: '$(Build.SourcesDirectory)\.binaries\bin\Release;SRV*http://symweb' + verbosityLevel: 'none' + env: + AzureServicesAuthConnectionString: RunAs=App;AppId=$(ApiScanClientId) \ No newline at end of file diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/AppSettings.cs b/src/DotNetCompilerPlatform/AppSettings.cs similarity index 73% rename from src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/AppSettings.cs rename to src/DotNetCompilerPlatform/AppSettings.cs index fc088b0..7576f17 100644 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/AppSettings.cs +++ b/src/DotNetCompilerPlatform/AppSettings.cs @@ -1,12 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Specialized; using System.Web.Configuration; namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { @@ -20,6 +15,8 @@ private static void LoadSettings(NameValueCollection appSettings) { if (!bool.TryParse(disableProfilingDuringCompilation, out _disableProfilingDuringCompilation)) { _disableProfilingDuringCompilation = true; } + + _roslynCompilerLocation = appSettings["aspnet:RoslynCompilerLocation"]; } private static void EnsureSettingsLoaded() { @@ -30,6 +27,8 @@ private static void EnsureSettingsLoaded() { lock (_lock) { if (!_settingsInitialized) { try { + // I think it should be safe to straight up use regular ConfigurationManager here... + // but if it ain't broke, don't fix it. LoadSettings(WebConfigurationManager.AppSettings); } finally { @@ -46,5 +45,13 @@ public static bool DisableProfilingDuringCompilation { return _disableProfilingDuringCompilation; } } + + private static string _roslynCompilerLocation = string.Empty; + public static string RoslynCompilerLocation { + get { + EnsureSettingsLoaded(); + return _roslynCompilerLocation; + } + } } } diff --git a/src/DotNetCompilerPlatform/CSharpCodeProvider.cs b/src/DotNetCompilerPlatform/CSharpCodeProvider.cs new file mode 100644 index 0000000..e0a74fc --- /dev/null +++ b/src/DotNetCompilerPlatform/CSharpCodeProvider.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.ComponentModel; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { + /// + /// Provides access to instances of the .NET Compiler Platform C# code generator and code compiler. + /// + [DesignerCategory("code")] + public sealed class CSharpCodeProvider : Microsoft.CSharp.CSharpCodeProvider { + private readonly IProviderOptions _providerOptions; + + /// + /// Default Constructor + /// + public CSharpCodeProvider() + : this((IProviderOptions)null) { + } + + /// + /// Creates an instance using the given ICompilerSettings + /// + /// + [Obsolete("ICompilerSettings is obsolete. Please update code to use IProviderOptions instead.", false)] + public CSharpCodeProvider(ICompilerSettings compilerSettings = null) { + _providerOptions = compilerSettings == null ? CompilationUtil.CSC2 : new ProviderOptions(compilerSettings); + } + + /// + /// Creates an instance using the given IProviderOptions + /// + /// + public CSharpCodeProvider(IProviderOptions providerOptions = null) { + _providerOptions = providerOptions ?? CompilationUtil.CSC2; + } + + /// + /// Creates an instance using the given IDictionary to create IProviderOptions + /// + /// + public CSharpCodeProvider(IDictionary providerOptions) + : this(CompilationUtil.CreateProviderOptions(providerOptions, CompilationUtil.CSC2)) { } + + /// + /// Gets an instance of the .NET Compiler Platform C# code compiler. + /// + /// An instance of the .NET Compiler Platform C# code compiler + [Obsolete("Callers should not use the ICodeCompiler interface and should instead use the methods directly on the CodeDomProvider class.")] + public override ICodeCompiler CreateCompiler() { + return new CSharpCompiler(this, _providerOptions); + } + } +} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs b/src/DotNetCompilerPlatform/CSharpCompiler.cs similarity index 86% rename from src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs rename to src/DotNetCompilerPlatform/CSharpCompiler.cs index 4076d74..e7ced22 100644 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCompiler.cs +++ b/src/DotNetCompilerPlatform/CSharpCompiler.cs @@ -14,8 +14,8 @@ internal class CSharpCompiler : Compiler { private static volatile Regex outputRegWithFileAndLine; private static volatile Regex outputRegSimple; - public CSharpCompiler(CodeDomProvider codeDomProvider, ICompilerSettings compilerSettings = null) - : base(codeDomProvider, compilerSettings) { + public CSharpCompiler(CodeDomProvider codeDomProvider, IProviderOptions providerOptions = null) + : base(codeDomProvider, providerOptions) { } protected override string FileExtension { @@ -69,14 +69,22 @@ protected override string FullPathsOption { protected override void FixUpCompilerParameters(CompilerParameters options) { base.FixUpCompilerParameters(options); - List noWarnStrings = new List(5); - noWarnStrings.AddRange(new string[] { "1659", "1699", "1701" }); - // disableObsoleteWarnings - noWarnStrings.Add("612"); // [Obsolete] without message - noWarnStrings.Add("618"); // [Obsolete("with message")] + // We used to magically add some ASP.net-centric options here. For compatibilities sake + // we will continue to do so in ASP.Net mode. If these are getting in the way for people + // though, disable ASP.Net mode and they will go away. (Sort of. These are the defaults + // in the XDT config transform, so they will already be here anyway for most folks.) + if (_providerOptions.UseAspNetSettings) + { + List noWarnStrings = new List(5); + noWarnStrings.AddRange(new string[] { "1659", "1699", "1701" }); - CompilationUtil.PrependCompilerOption(options, "/nowarn:" + String.Join(";", noWarnStrings)); + // disableObsoleteWarnings + noWarnStrings.Add("612"); // [Obsolete] without message + noWarnStrings.Add("618"); // [Obsolete("with message")] + + CompilationUtil.PrependCompilerOption(options, "/nowarn:" + String.Join(";", noWarnStrings)); + } } protected override string CmdArgsFromParameters(CompilerParameters parameters) { diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Compiler.cs b/src/DotNetCompilerPlatform/Compiler.cs similarity index 86% rename from src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Compiler.cs rename to src/DotNetCompilerPlatform/Compiler.cs index deefa2f..445088b 100644 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Compiler.cs +++ b/src/DotNetCompilerPlatform/Compiler.cs @@ -16,14 +16,15 @@ namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { internal abstract class Compiler : ICodeCompiler { private readonly CodeDomProvider _codeDomProvider; - private readonly ICompilerSettings _compilerSettings; + protected readonly IProviderOptions _providerOptions; private string _compilerFullPath = null; private const string CLR_PROFILING_SETTING = "COR_ENABLE_PROFILING"; private const string DISABLE_PROFILING = "0"; - public Compiler(CodeDomProvider codeDomProvider, ICompilerSettings compilerSettings) { + public Compiler(CodeDomProvider codeDomProvider, IProviderOptions providerOptions) + { this._codeDomProvider = codeDomProvider; - this._compilerSettings = compilerSettings; + this._providerOptions = providerOptions; } public CompilerResults CompileAssemblyFromDom(CompilerParameters options, CodeCompileUnit compilationUnit) { @@ -49,9 +50,10 @@ public CompilerResults CompileAssemblyFromDomBatch(CompilerParameters options, C try { var sources = compilationUnits.Select(c => { - var writer = new StringWriter(); - _codeDomProvider.GenerateCodeFromCompileUnit(c, writer, new CodeGeneratorOptions()); - return writer.ToString(); + using (var writer = new StringWriter()) { + _codeDomProvider.GenerateCodeFromCompileUnit(c, writer, new CodeGeneratorOptions()); + return writer.ToString(); + } }); return FromSourceBatch(options, sources.ToArray()); @@ -132,7 +134,7 @@ protected abstract string FileExtension { protected virtual string CompilerName { get { if (null == _compilerFullPath) { - _compilerFullPath = _compilerSettings.CompilerFullPath; + _compilerFullPath = _providerOptions.CompilerFullPath; // Try opening the file to make sure the compiler exist. This will throw an exception // if it doesn't @@ -164,10 +166,15 @@ private string GetCompilationArgumentString(CompilerParameters options) { // CodeDom sets TreatWarningAsErrors to true whenever warningLevel is non-zero. // However, TreatWarningAsErrors should be false by default. // And users should be able to set the value by set the value of option "WarnAsError". - // ASP.Net does fix this "WarnAsError" option, but only for old CodeDom providers (CSharp/VB). - // So we need to do this correction here. - private static void FixTreatWarningsAsErrors(CompilerParameters parameters) { - parameters.TreatWarningsAsErrors = false; + // ASP.Net does fix this option in a like named function, but only for old CodeDom providers (CSharp/VB). + // The old ASP.Net fix was to set TreatWarningAsErrors to false anytime '/warnaserror' was + // detected in the compiler command line options, thus allowing the user-specified + // option to prevail. In these CodeDom providers though, users have control through + // the 'WarnAsError' provider option as well as manual control over the command + // line args. 'WarnAsError' will default to false but can be set by the user. + // So just go with the 'WarnAsError' provider option here. + private void FixTreatWarningsAsErrors(CompilerParameters parameters) { + parameters.TreatWarningsAsErrors = _providerOptions.WarnAsError; } private CompilerResults FromSourceBatch(CompilerParameters options, string[] sources) { @@ -186,27 +193,28 @@ private CompilerResults FromSourceBatch(CompilerParameters options, string[] sou // the extra try-catch is here to mitigate exception filter injection attacks. try { - WindowsImpersonationContext impersonation = RevertImpersonation(); - try { - for (int i = 0; i < sources.Length; i++) { - string name = options.TempFiles.AddExtension(i + FileExtension); - var temp = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.Read); - try { - using (var sw = new StreamWriter(temp, Encoding.UTF8)) { - sw.Write(sources[i]); - sw.Flush(); + using (WindowsImpersonationContext impersonation = RevertImpersonation()) { + try { + for (int i = 0; i < sources.Length; i++) { + string name = options.TempFiles.AddExtension(i + FileExtension); + var temp = new FileStream(name, FileMode.Create, FileAccess.Write, FileShare.Read); + try { + using (var sw = new StreamWriter(temp, Encoding.UTF8)) { + sw.Write(sources[i]); + sw.Flush(); + } } + finally { + temp.Close(); + } + filenames[i] = name; } - finally { - temp.Close(); - } - filenames[i] = name; - } - results = FromFileBatch(options, filenames); - } - finally { - ReImpersonate(impersonation); + results = FromFileBatch(options, filenames); + } + finally { + ReImpersonate(impersonation); + } } } catch { @@ -277,8 +285,8 @@ private CompilerResults FromFileBatch(CompilerParameters options, string[] fileN } // Appending TTL to the command line arguments. - if (_compilerSettings.CompilerServerTimeToLive > 0) { - args = string.Format("/shared /keepalive:\"{0}\" {1}", _compilerSettings.CompilerServerTimeToLive, args); + if (_providerOptions.CompilerServerTimeToLive > 0) { + args = string.Format("/shared /keepalive:\"{0}\" {1}", _providerOptions.CompilerServerTimeToLive, args); } Compile(options, diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.csproj b/src/DotNetCompilerPlatform/DotNetCompilerPlatform.csproj similarity index 64% rename from src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.csproj rename to src/DotNetCompilerPlatform/DotNetCompilerPlatform.csproj index 0cb3836..bf688ac 100644 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.csproj +++ b/src/DotNetCompilerPlatform/DotNetCompilerPlatform.csproj @@ -1,5 +1,5 @@  - + @@ -10,18 +10,14 @@ Properties Microsoft.CodeDom.Providers.DotNetCompilerPlatform Microsoft.CodeDom.Providers.DotNetCompilerPlatform - v4.5 + v4.7.2 512 + + $(OutputPath)$(AssemblyName).xml + ..\..\ true true $(RepositoryRoot)src\35MSSharedLib1024.snk - SAK - SAK - SAK - SAK - $(OutputPath)$(AssemblyName).xml - ..\..\ - true true @@ -33,7 +29,7 @@ ..\obj\ - pdbonly + portable true TRACE prompt @@ -55,35 +51,14 @@ - - Component - + - + + - - Component - + - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Properties/AssemblyInfo.cs b/src/DotNetCompilerPlatform/Properties/AssemblyInfo.cs similarity index 100% rename from src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Properties/AssemblyInfo.cs rename to src/DotNetCompilerPlatform/Properties/AssemblyInfo.cs diff --git a/src/DotNetCompilerPlatform/Util/CompilationUtil.cs b/src/DotNetCompilerPlatform/Util/CompilationUtil.cs new file mode 100644 index 0000000..debd55c --- /dev/null +++ b/src/DotNetCompilerPlatform/Util/CompilationUtil.cs @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { + internal static class CompilationUtil { + private const int DefaultCompilerServerTTL = 10; // 10 seconds + private const int DefaultCompilerServerTTLInDevEnvironment = 60 * 15; // 15 minutes + + static CompilationUtil() + { + CSC2 = GetProviderOptionsFor(".cs"); + VBC2 = GetProviderOptionsFor(".vb"); + + if (IsDebuggerAttached) + { + Environment.SetEnvironmentVariable("IN_DEBUG_MODE", "1", EnvironmentVariableTarget.Process); + } + } + + public static IProviderOptions CSC2 { get; } + + public static IProviderOptions VBC2 { get; } + + internal static IProviderOptions CreateProviderOptions(IDictionary options, IProviderOptions baseOptions) + { + Dictionary allOptions = null; + + // Copy the base options + ProviderOptions providerOpts = new ProviderOptions(baseOptions); + + // Update as necessary. Case-sensitive. + foreach (var option in options) + { + if (String.IsNullOrWhiteSpace(option.Key)) + continue; + + switch (option.Key) + { + case "CompilerFullPath": + providerOpts.CompilerFullPath = option.Value; + break; + + case "CompilerServerTimeToLive": + if (Int32.TryParse(option.Value, out int newTTL)) + providerOpts.CompilerServerTimeToLive = newTTL; + break; + + case "CompilerVersion": + providerOpts.CompilerVersion = option.Value; + break; + + case "WarnAsError": + if (Boolean.TryParse(option.Value, out bool warnAsError)) + providerOpts.WarnAsError = warnAsError; + break; + + case "AllOptions": + allOptions = allOptions ?? new Dictionary(providerOpts.AllOptions); + allOptions.Remove(option.Key); + allOptions.Add(option.Key, option.Value); + break; + + default: + break; + } + } + + if (allOptions != null) + providerOpts.AllOptions = allOptions; + + return providerOpts; + } + + public static IProviderOptions GetProviderOptionsFor(string fileExt) + { + // + // AllOptions + // + IDictionary options = GetProviderOptionsCollection(fileExt); + + // + // CompilerFullPath + // + string compilerFullPath = Environment.GetEnvironmentVariable("ROSLYN_COMPILER_LOCATION"); + if (String.IsNullOrEmpty(compilerFullPath)) + compilerFullPath = AppSettings.RoslynCompilerLocation; + if (String.IsNullOrEmpty(compilerFullPath)) + options.TryGetValue("CompilerLocation", out compilerFullPath); + if (String.IsNullOrEmpty(compilerFullPath)) + compilerFullPath = CompilerDefaultPath(); + + if (!String.IsNullOrWhiteSpace(fileExt)) + { + // If we have a file extension, try to infer the compiler to use + // TODO: Should we also check compilerFullPath to assert it is a Directory and not a file? + if (fileExt.Equals(".cs", StringComparison.InvariantCultureIgnoreCase) || fileExt.Equals("cs", StringComparison.InvariantCultureIgnoreCase)) + compilerFullPath = Path.Combine(compilerFullPath, "csc.exe"); + else if (fileExt.Equals(".vb", StringComparison.InvariantCultureIgnoreCase) || fileExt.Equals("vb", StringComparison.InvariantCultureIgnoreCase)) + compilerFullPath = Path.Combine(compilerFullPath, "vbc.exe"); + } + + + // + // CompilerServerTimeToLive - default 10 seconds in production, 15 minutes in dev environment. + // + string ttlstr = Environment.GetEnvironmentVariable("VBCSCOMPILER_TTL"); + if (String.IsNullOrEmpty(ttlstr)) + options.TryGetValue("CompilerServerTTL", out ttlstr); + if (!Int32.TryParse(ttlstr, out int ttl)) + { + ttl = DefaultCompilerServerTTL; + + if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("DEV_ENVIRONMENT")) || + !String.IsNullOrEmpty(Environment.GetEnvironmentVariable("IN_DEBUG_MODE")) || + CompilationUtil.IsDebuggerAttached) + { + ttl = DefaultCompilerServerTTLInDevEnvironment; + } + } + + // + // CompilerVersion - if this is null, we don't care. + // + options.TryGetValue("CompilerVersion", out string compilerVersion); // Failure to parse sets to null + + // + // WarnAsError - default false. + // + bool warnAsError = false; + if (options.TryGetValue("WarnAsError", out string sWAE)) + { + Boolean.TryParse(sWAE, out warnAsError); // Failure to parse sets to 'false' + } + + // + // UseAspNetSettings - default true. This was meant to be an ASP.Net support package first and foremost. + // + bool useAspNetSettings = true; + if (options.TryGetValue("UseAspNetSettings", out string sUANS)) + { + // Failure to parse sets to 'false', but we want to keep the default 'true'. + if (!Boolean.TryParse(sUANS, out useAspNetSettings)) + useAspNetSettings = true; + } + + ProviderOptions providerOptions = new ProviderOptions() + { + CompilerFullPath = compilerFullPath, + CompilerServerTimeToLive = ttl, + CompilerVersion = compilerVersion, + WarnAsError = warnAsError, + UseAspNetSettings = useAspNetSettings, + AllOptions = options + }; + + return providerOptions; + } + + internal static IDictionary GetProviderOptionsCollection(string fileExt) + { + Dictionary opts = new Dictionary(); + + if (!CodeDomProvider.IsDefinedExtension(fileExt)) + return new ReadOnlyDictionary(opts); + + CompilerInfo ci = CodeDomProvider.GetCompilerInfo(CodeDomProvider.GetLanguageFromExtension(fileExt)); + + if (ci == null) + return new ReadOnlyDictionary(opts); + + // There is a fun little comment about this property in the framework code about making it + // public after 3.5. Guess that didn't happen. Oh well. :) + PropertyInfo pi = ci.GetType().GetProperty("ProviderOptions", + BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance); + if (pi == null) + return new ReadOnlyDictionary(opts); + + return new ReadOnlyDictionary((IDictionary)pi.GetValue(ci, null)); + } + + internal static void PrependCompilerOption(CompilerParameters compilParams, string compilerOptions) + { + if (compilParams.CompilerOptions == null) + { + compilParams.CompilerOptions = compilerOptions; + } + else + { + compilParams.CompilerOptions = compilerOptions + " " + compilParams.CompilerOptions; + } + } + + internal static string CompilerDefaultPath() + { + string webPath = @"bin\roslyn"; + string appPath = @"roslyn"; + + // Check bin folder first + string compilerFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, webPath); + + // Then appdomain base + if (!Directory.Exists(compilerFullPath)) + compilerFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, appPath); + + return compilerFullPath; + } + + internal static bool IsDebuggerAttached + { + get { + return IsDebuggerPresent() || Debugger.IsAttached; + } + } + + [DllImport("kernel32.dll")] + private extern static bool IsDebuggerPresent(); + } +} diff --git a/src/DotNetCompilerPlatform/Util/ICompilerSettings.cs b/src/DotNetCompilerPlatform/Util/ICompilerSettings.cs new file mode 100644 index 0000000..21b41cb --- /dev/null +++ b/src/DotNetCompilerPlatform/Util/ICompilerSettings.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { + + /// + /// Provides settings for the C# and VB CodeProviders + /// + [Obsolete("ICompilerSettings is obsolete. Please update code to use IProviderOptions instead.", false)] + public interface ICompilerSettings { + + /// + /// The full path to csc.exe or vbc.exe + /// + string CompilerFullPath { get; } + + /// + /// TTL in seconds + /// + int CompilerServerTimeToLive { get; } + } +} diff --git a/src/DotNetCompilerPlatform/Util/IProviderOptions.cs b/src/DotNetCompilerPlatform/Util/IProviderOptions.cs new file mode 100644 index 0000000..e135446 --- /dev/null +++ b/src/DotNetCompilerPlatform/Util/IProviderOptions.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { + +#pragma warning disable CS0618 + + /// + /// Provides settings for the C# and VB CodeProviders + /// + public interface IProviderOptions : ICompilerSettings { + + // These come from ICompilerSettings. + ///// + ///// The full path to csc.exe or vbc.exe + ///// + //string CompilerFullPath { get; } + + ///// + ///// TTL in seconds + ///// + //int CompilerServerTimeToLive { get; } + + /// + /// A string representing the in-box .Net Framework compiler version to be used. + /// Not applicable to this Roslyn-based package which contains it's own compiler. + /// + string CompilerVersion { get; } + + /// + /// Returns true if the codedom provider has warnAsError set to true + /// + bool WarnAsError { get; } + + /// + /// Returns true if the codedom provider is requesting to use similar default + /// compiler options as ASP.Net does with in-box .Net Framework compilers. + /// These options are programatically enforced on top of parameters passed + /// in to the codedom provider. + /// + bool UseAspNetSettings { get; } + + /// + /// Returns the entire set of options - known or not - as configured in <providerOptions> + /// + IDictionary AllOptions { get; } + } +#pragma warning restore CS0618 + +} diff --git a/src/DotNetCompilerPlatform/Util/ProviderOptions.cs b/src/DotNetCompilerPlatform/Util/ProviderOptions.cs new file mode 100644 index 0000000..2bd13e4 --- /dev/null +++ b/src/DotNetCompilerPlatform/Util/ProviderOptions.cs @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { + + /// + /// A set of options for the C# and VB CodeProviders. + /// + public sealed class ProviderOptions : IProviderOptions { + + private IDictionary _allOptions; + + /// + /// Create a default set of options for the C# and VB CodeProviders. + /// + public ProviderOptions() + { + this.CompilerFullPath = null; + this.CompilerVersion = null; + this.WarnAsError = false; + + // To be consistent, make sure there is always a dictionary here. It is less than ideal + // for some parts of code to be checking AllOptions.count and some part checking + // for AllOptions == null. + this.AllOptions = new ReadOnlyDictionary(new Dictionary()); + + // This results in no keep-alive for the compiler. This will likely result in + // slower performance for any program that calls out the the compiler any + // significant number of times. This is why the CompilerUtil.GetProviderOptionsFor + // does not leave this as 0. + this.CompilerServerTimeToLive = 0; + + // This is different from the default that the CompilerUtil.GetProviderOptionsFor + // factory method uses. The primary known user of the factory method is us, and + // this package is first intended to support ASP.Net. However, if somebody is + // creating an instance of this directly, they are probably not an ASP.Net + // project. Thus the different default here. + this.UseAspNetSettings = false; + } + + /// + /// Create a set of options for the C# or VB CodeProviders using the specified inputs. + /// + public ProviderOptions(IProviderOptions opts) + { + this.CompilerFullPath = opts.CompilerFullPath; + this.CompilerServerTimeToLive = opts.CompilerServerTimeToLive; + this.CompilerVersion = opts.CompilerVersion; + this.WarnAsError = opts.WarnAsError; + this.UseAspNetSettings = opts.UseAspNetSettings; + this.AllOptions = new ReadOnlyDictionary(opts.AllOptions); + } + + /// + /// Create a set of options for the C# or VB CodeProviders using some specified inputs. + /// + public ProviderOptions(string compilerFullPath, int compilerServerTimeToLive) : this() + { + this.CompilerFullPath = compilerFullPath; + this.CompilerServerTimeToLive = compilerServerTimeToLive; + } + +#pragma warning disable CS0618 + internal ProviderOptions(ICompilerSettings settings) : this(settings.CompilerFullPath, settings.CompilerServerTimeToLive) { } +#pragma warning restore CS0618 + + /// + /// The full path to csc.exe or vbc.exe + /// + public string CompilerFullPath { get; internal set; } + + /// + /// TTL in seconds + /// + public int CompilerServerTimeToLive { get; internal set; } + + /// + /// Used by in-box framework code providers to determine which compat version of the compiler to use. + /// + public string CompilerVersion { get; internal set; } + + // smolloy todo debug degub - Does it really override everything? Is that the right thing to do? + /// + /// Treat all warnings as errors. Will override defaults and command-line options given for a compiler. + /// + public bool WarnAsError { get; internal set; } + + /// + /// Use the set of compiler options that was traditionally added programatically for ASP.Net. + /// + public bool UseAspNetSettings { get; internal set; } + + /// + /// A collection of all <providerOptions> specified in config for the given CodeDomProvider. + /// + public IDictionary AllOptions { + get { + return _allOptions; + } + internal set { + _allOptions = (value != null) ? new ReadOnlyDictionary(value) : null; + } + } + } +} diff --git a/src/DotNetCompilerPlatform/VBCodeProvider.cs b/src/DotNetCompilerPlatform/VBCodeProvider.cs new file mode 100644 index 0000000..a7f7eb4 --- /dev/null +++ b/src/DotNetCompilerPlatform/VBCodeProvider.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.ComponentModel; + +namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { + /// + /// Provides access to instances of the .NET Compiler Platform VB code generator and code compiler. + /// + [DesignerCategory("code")] + public sealed class VBCodeProvider : Microsoft.VisualBasic.VBCodeProvider { + private readonly IProviderOptions _providerOptions; + + /// + /// Default Constructor + /// + public VBCodeProvider() + : this((IProviderOptions)null) { + } + + /// + /// Creates an instance using the given ICompilerSettings + /// + /// + [Obsolete("ICompilerSettings is obsolete. Please update code to use IProviderOptions instead.", false)] + public VBCodeProvider(ICompilerSettings compilerSettings = null) { + _providerOptions = compilerSettings == null ? CompilationUtil.VBC2 : new ProviderOptions(compilerSettings); + } + + /// + /// Creates an instance using the given ICompilerSettings + /// + /// + public VBCodeProvider(IProviderOptions providerOptions = null) { + _providerOptions = providerOptions ?? CompilationUtil.VBC2; + } + + /// + /// Creates an instance using the given IDictionary to create IProviderOptions + /// + /// + public VBCodeProvider(IDictionary providerOptions) + : this(CompilationUtil.CreateProviderOptions(providerOptions, CompilationUtil.VBC2)) { } + + /// + /// Gets an instance of the .NET Compiler Platform VB code compiler. + /// + /// An instance of the .NET Compiler Platform VB code compiler + [Obsolete("Callers should not use the ICodeCompiler interface and should instead use the methods directly on the CodeDomProvider class.")] + public override ICodeCompiler CreateCompiler() { + return new VBCompiler(this, _providerOptions); + } + } +} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/VBCompiler.cs b/src/DotNetCompilerPlatform/VBCompiler.cs similarity index 85% rename from src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/VBCompiler.cs rename to src/DotNetCompilerPlatform/VBCompiler.cs index a183a01..80521cb 100644 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/VBCompiler.cs +++ b/src/DotNetCompilerPlatform/VBCompiler.cs @@ -19,8 +19,8 @@ internal class VBCompiler : Compiler { private static volatile Regex outputReg; - public VBCompiler(CodeDomProvider codeDomProvider, ICompilerSettings compilerSettings = null) - : base(codeDomProvider, compilerSettings) { + public VBCompiler(CodeDomProvider codeDomProvider, IProviderOptions providerOptions = null) + : base(codeDomProvider, providerOptions) { } protected override string FileExtension { @@ -52,30 +52,38 @@ protected override void ProcessCompilerOutputLine(CompilerResults results, strin protected override void FixUpCompilerParameters(CompilerParameters options) { base.FixUpCompilerParameters(options); - // Hard code OptionInfer to true, which is the default value in the root web config. - // TODO This code should be removed once CodeDom directly supports provider options such as WarnAsError, OptionInfer - CompilationUtil.PrependCompilerOption(options, " /optionInfer+"); - List noWarnStrings = new List(3); + // We used to magically add some ASP.net-centric options here. For compatibilities sake + // we will continue to do so in ASP.Net mode. If these are getting in the way for people + // though, disable ASP.Net mode and they will go away. (Sort of. These mostly are the defaults + // in the XDT config transform, so they will already be here anyway for most folks.) + if (_providerOptions.UseAspNetSettings) + { + // Hard code OptionInfer to true, which is the default value in the root web config. + // TODO This code should be removed once CodeDom directly supports provider options such as WarnAsError, OptionInfer + CompilationUtil.PrependCompilerOption(options, " /optionInfer+"); - // If VB, add all the imported namespaces on the command line (DevDiv 21499). - // This is VB only because other languages don't support global command line - // namespace imports. - AddVBGlobalNamespaceImports(options); + List noWarnStrings = new List(3); - // Add any command line flags needed to support the My.* feature - AddVBMyFlags(options); + // If VB, add all the imported namespaces on the command line (DevDiv 21499). + // This is VB only because other languages don't support global command line + // namespace imports. + AddVBGlobalNamespaceImports(options); - // Ignore vb warning that complains about assemblyKeyName (Dev10 662544) - // but only for target 3.5 and above (715329) - noWarnStrings.Add("41008"); + // Add any command line flags needed to support the My.* feature + AddVBMyFlags(options); - // disable ObsoleteWarnings - noWarnStrings.Add("40000"); // [Obsolete("with message")] - noWarnStrings.Add("40008"); // [Obsolete] without message + // Ignore vb warning that complains about assemblyKeyName (Dev10 662544) + // but only for target 3.5 and above (715329) + noWarnStrings.Add("41008"); - if (noWarnStrings.Count > 0) { - CompilationUtil.PrependCompilerOption(options, "/nowarn:" + String.Join(",", noWarnStrings)); + // disable ObsoleteWarnings + noWarnStrings.Add("40000"); // [Obsolete("with message")] + noWarnStrings.Add("40008"); // [Obsolete] without message + + if (noWarnStrings.Count > 0) { + CompilationUtil.PrependCompilerOption(options, "/nowarn:" + String.Join(",", noWarnStrings)); + } } } @@ -100,8 +108,8 @@ protected override string CmdArgsFromParameters(CompilerParameters parameters) { string coreAssemblyFileName = parameters.CoreAssemblyFileName; if (String.IsNullOrWhiteSpace(parameters.CoreAssemblyFileName)) { - string probableCoreAssemblyFilePath; - if (TryGetProbableCoreAssemblyFilePath(parameters, out probableCoreAssemblyFilePath)) { + if (TryGetProbableCoreAssemblyFilePath(parameters, out string probableCoreAssemblyFilePath)) + { coreAssemblyFileName = probableCoreAssemblyFilePath; } } diff --git a/src/DotNetCompilerPlatformTasks/CheckIfVBCSCompilerWillOverride.cs b/src/DotNetCompilerPlatformTasks/CheckIfVBCSCompilerWillOverride.cs new file mode 100644 index 0000000..a940cfd --- /dev/null +++ b/src/DotNetCompilerPlatformTasks/CheckIfVBCSCompilerWillOverride.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace DotNetCompilerPlatformTasks +{ + public class CheckIfVBCSCompilerWillOverride : Task + { + [Required] + public string Src { get; set; } + [Required] + public string Dest { get; set; } + + [Output] + public bool WillOverride { get; set; } + + public override bool Execute() + { + WillOverride = false; + + try + { + WillOverride = File.Exists(Src) && File.Exists(Dest) && (File.GetLastWriteTime(Src) != File.GetLastWriteTime(Dest)); + } + catch { return false; } + + return true; + } + } +} diff --git a/src/DotNetCompilerPlatformTasks/DotNetCompilerPlatformTasks.csproj b/src/DotNetCompilerPlatformTasks/DotNetCompilerPlatformTasks.csproj new file mode 100644 index 0000000..d0b05c3 --- /dev/null +++ b/src/DotNetCompilerPlatformTasks/DotNetCompilerPlatformTasks.csproj @@ -0,0 +1,29 @@ + + + + + netstandard2.0 + false + true + false + true + true + $(RepositoryRoot)src\35MSSharedLib1024.snk + + + + full + + + + portable + + + + + all + + + + + diff --git a/src/DotNetCompilerPlatformTasks/KillProcess.cs b/src/DotNetCompilerPlatformTasks/KillProcess.cs new file mode 100644 index 0000000..d935144 --- /dev/null +++ b/src/DotNetCompilerPlatformTasks/KillProcess.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; +using System.Linq; +using System.Management; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace DotNetCompilerPlatformTasks +{ + public class KillProcess : Task + { + [Required] + public string ProcessName { get; set; } + [Required] + public string ImagePath { get; set; } + + public override bool Execute() + { + try + { + foreach (var p in Process.GetProcessesByName(ProcessName)) + { + var wmiQuery = "SELECT ProcessId, ExecutablePath FROM Win32_Process WHERE ProcessId = " + p.Id; + using (var searcher = new ManagementObjectSearcher(wmiQuery)) + { + using (var results = searcher.Get()) + { + var mo = results.Cast().FirstOrDefault(); + if (mo != null) + { + var path = (string)mo["ExecutablePath"]; + var executablePath = path ?? string.Empty; + Log.LogMessage("ExecutablePath is {0}", executablePath); + + if (executablePath.StartsWith(ImagePath, StringComparison.OrdinalIgnoreCase)) + { + p.Kill(); + p.WaitForExit(); + Log.LogMessage("{0} is killed", executablePath); + break; + } + } + } + } + } + } + catch (Exception ex) + { + Log.LogWarning(ex.Message); + } + return true; + } + } +} diff --git a/src/DotNetCompilerPlatformTasks/UpdateCompilerConfigRecord.cs b/src/DotNetCompilerPlatformTasks/UpdateCompilerConfigRecord.cs new file mode 100644 index 0000000..08b6d70 --- /dev/null +++ b/src/DotNetCompilerPlatformTasks/UpdateCompilerConfigRecord.cs @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Xml; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace DotNetCompilerPlatformTasks +{ + public class UpdateCompilerConfigRecord : Task + { + [Required] + public string ConfigFile { get; set; } + [Required] + public string Extension { get; set; } + [Required] + public string Language { get; set; } + [Required] + public string WarningLevel { get; set; } + [Required] + public string Options { get; set; } + [Required] + public string CompilerType { get; set; } + + private readonly string singleTab = " "; + + + public override bool Execute() + { + try + { + XmlDocument config = new XmlDocument() { PreserveWhitespace = true }; + config.Load(ConfigFile); + + // Look for existing 'compiler' record first. Keying on 'extension' is a little dubious since that attribute can + // technically be a ';' separated list of extensions... but it's what we always seemed to do in the past. + XmlNode compiler = config.SelectSingleNode($"/configuration/system.codedom/compilers/compiler[@extension='{Extension}']"); + + // Create the 'compiler' record if not found. + if (compiler == null) + { + string indent = ""; + XmlElement e = CreateElement(config, "system.codedom/compilers", "compiler", ref indent); + e.SetAttribute("language", Language); + e.SetAttribute("extension", Extension); + e.SetAttribute("warningLevel", WarningLevel); + e.SetAttribute("compilerOptions", Options); + e.SetAttribute("type", CompilerType); + + // Add a 'providerOption' to not do ASP.Net "magic" within the codedom provider if not working on web.config + if (!ConfigFile.EndsWith("web.config", System.StringComparison.InvariantCultureIgnoreCase)) + { + XmlElement pOpt = CreateIndentedElement(e, "providerOption", indent + singleTab); + pOpt.SetAttribute("name", "UseAspNetSettings"); + pOpt.SetAttribute("value", "false"); + } + + config.Save(ConfigFile); + return true; + } + + // Otherwise, leave the existing compiler alone - including any 'providerOptions' - except... + // Ensure the 'type' value is current. + var typeAttr = compiler.Attributes["type"]; + if (typeAttr == null || string.Compare(typeAttr.Value, CompilerType, System.StringComparison.InvariantCultureIgnoreCase) != 0) + { + typeAttr = config.CreateAttribute("type"); + typeAttr.Value = CompilerType; + compiler.Attributes.SetNamedItem(typeAttr); + config.Save(ConfigFile); + } + } + catch (Exception e) + { + Log.LogErrorFromException(e); + return false; + } + + return true; + } + + private XmlElement CreateElement(XmlDocument doc, string path, string name, ref string indent) + { + XmlElement current = doc.DocumentElement; + + foreach (var partName in path.Trim('/').Split('/')) + { + if (string.IsNullOrWhiteSpace(partName)) + continue; + + current = (current.SelectSingleNode(partName) as XmlElement) ?? CreateIndentedElement(current, partName, indent); + indent += singleTab; + } + + return CreateIndentedElement(current, name, indent); + } + + private XmlElement CreateIndentedElement(XmlNode parent, string name, string indent) + { + if (!parent.HasChildNodes) + parent.AppendChild(parent.OwnerDocument.CreateWhitespace(Environment.NewLine + indent + singleTab)); + else + parent.AppendChild(parent.OwnerDocument.CreateWhitespace(singleTab)); + + XmlElement e = parent.AppendChild(parent.OwnerDocument.CreateElement(name)) as XmlElement; + parent.AppendChild(parent.OwnerDocument.CreateWhitespace(Environment.NewLine + indent)); + return e; + } + } +} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCodeProvider.cs b/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCodeProvider.cs deleted file mode 100644 index bd3ac31..0000000 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/CSharpCodeProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.CodeDom.Compiler; - -namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { - /// - /// Provides access to instances of the .NET Compiler Platform C# code generator and code compiler. - /// - public sealed class CSharpCodeProvider : Microsoft.CSharp.CSharpCodeProvider { - private ICompilerSettings _compilerSettings; - - /// - /// Default Constructor - /// - public CSharpCodeProvider() - : this(null) { - } - - // Constructor used for unit test purpose - internal CSharpCodeProvider(ICompilerSettings compilerSettings = null) { - _compilerSettings = compilerSettings == null ? CompilationSettingsHelper.CSC2 : compilerSettings; - } - - /// - /// Gets an instance of the .NET Compiler Platform C# code compiler. - /// - /// An instance of the .NET Compiler Platform C# code compiler - [Obsolete("Callers should not use the ICodeCompiler interface and should instead use the methods directly on the CodeDomProvider class.")] - public override ICodeCompiler CreateCompiler() { - return new CSharpCompiler(this, _compilerSettings); - } - } -} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/CompilationSettings.cs b/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/CompilationSettings.cs deleted file mode 100644 index f3add69..0000000 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/CompilationSettings.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; - -namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { - internal sealed class CompilerSettings : ICompilerSettings { - - private readonly string _compilerFullPath; - private readonly int _compilerServerTimeToLive = 0; // seconds - - public CompilerSettings(string compilerFullPath, int compilerServerTimeToLive) { - if (string.IsNullOrEmpty(compilerFullPath)) { - throw new ArgumentNullException("compilerFullPath"); - } - - _compilerFullPath = compilerFullPath; - _compilerServerTimeToLive = compilerServerTimeToLive; - } - - string ICompilerSettings.CompilerFullPath { - get { - return _compilerFullPath; - } - } - - int ICompilerSettings.CompilerServerTimeToLive { - get{ - return _compilerServerTimeToLive; - } - } - } - - internal static class CompilationSettingsHelper { - private const int DefaultCompilerServerTTL = 10; //seconds - private const int DefaultCompilerServerTTLInDevEnvironment = 60 * 15; - private const string DevEnvironmentVariableName = "DEV_ENVIRONMENT"; - private const string DebuggerAttachedEnvironmentVariable = "IN_DEBUG_MODE"; - private const string CustomTTLEnvironmentVariableName = "VBCSCOMPILER_TTL"; // the setting value is in seconds - // Full path of the directory that contains the Roslyn binaries - // and the hosting process has permission to access that path - private const string CustomRoslynCompilerLocation = "ROSLYN_COMPILER_LOCATION"; - - private static ICompilerSettings _csc; - private static ICompilerSettings _vb; - - static CompilationSettingsHelper() { - var ttl = DefaultCompilerServerTTL; - var devEnvironmentSetting = Environment.GetEnvironmentVariable(DevEnvironmentVariableName, EnvironmentVariableTarget.Process); - var debuggerAttachedEnvironmentSetting = Environment.GetEnvironmentVariable(DebuggerAttachedEnvironmentVariable, - EnvironmentVariableTarget.Process); - var customTtlSetting = Environment.GetEnvironmentVariable(CustomTTLEnvironmentVariableName, EnvironmentVariableTarget.Process); - var isDebuggerAttached = IsDebuggerAttached; - int customTtl; - - // custom TTL setting always win - if(int.TryParse(customTtlSetting, out customTtl)) - { - ttl = customTtl; - } - else - { - if (!string.IsNullOrEmpty(devEnvironmentSetting) || - !string.IsNullOrEmpty(debuggerAttachedEnvironmentSetting) || - isDebuggerAttached) - { - ttl = DefaultCompilerServerTTLInDevEnvironment; - } - } - - var customRoslynCompilerLocation = Environment.GetEnvironmentVariable(CustomRoslynCompilerLocation, EnvironmentVariableTarget.Process); - if(customRoslynCompilerLocation != null) - { - _csc = new CompilerSettings($"{customRoslynCompilerLocation}\\csc.exe", ttl); - _vb = new CompilerSettings($"{customRoslynCompilerLocation}\\vbc.exe", ttl); - } - else - { - _csc = new CompilerSettings(CompilerFullPath(@"bin\roslyn\csc.exe"), ttl); - _vb = new CompilerSettings(CompilerFullPath(@"bin\roslyn\vbc.exe"), ttl); - } - - if (isDebuggerAttached) { - Environment.SetEnvironmentVariable(DebuggerAttachedEnvironmentVariable, "1", EnvironmentVariableTarget.Process); - } - } - - public static ICompilerSettings CSC2 { - get { - return _csc; - } - } - - public static ICompilerSettings VBC2 { - get { - return _vb; - } - } - - private static string CompilerFullPath(string relativePath) { - string compilerFullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, relativePath); - return compilerFullPath; - } - - private static bool IsDebuggerAttached { - get { - return IsDebuggerPresent() || Debugger.IsAttached; - } - } - - [DllImport("kernel32.dll")] - private extern static bool IsDebuggerPresent(); - } -} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/CompilationUtil.cs b/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/CompilationUtil.cs deleted file mode 100644 index f1edd55..0000000 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/CompilationUtil.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.CodeDom.Compiler; - -namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { - internal static class CompilationUtil { - internal static void PrependCompilerOption(CompilerParameters compilParams, string compilerOptions) { - if (compilParams.CompilerOptions == null) { - compilParams.CompilerOptions = compilerOptions; - } - else { - compilParams.CompilerOptions = compilerOptions + " " + compilParams.CompilerOptions; - } - } - } -} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/ICompilerSettings.cs b/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/ICompilerSettings.cs deleted file mode 100644 index 0430f9d..0000000 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Util/ICompilerSettings.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { - internal interface ICompilerSettings { - string CompilerFullPath { get; } - - // TTL in seconds - int CompilerServerTimeToLive { get; } - } -} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/VBCodeProvider.cs b/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/VBCodeProvider.cs deleted file mode 100644 index 3d02b4a..0000000 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/VBCodeProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.CodeDom.Compiler; - -namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatform { - /// - /// Provides access to instances of the .NET Compiler Platform VB code generator and code compiler. - /// - public sealed class VBCodeProvider : Microsoft.VisualBasic.VBCodeProvider { - private ICompilerSettings _compilerSettings; - - /// - /// Default Constructor - /// - public VBCodeProvider() - : this(null) { - } - - // Constructor used for unit test purpose - internal VBCodeProvider(ICompilerSettings compilerSettings = null) { - _compilerSettings = compilerSettings == null ? CompilationSettingsHelper.VBC2 : compilerSettings; - } - - /// - /// Gets an instance of the .NET Compiler Platform VB code compiler. - /// - /// An instance of the .NET Compiler Platform VB code compiler - [Obsolete("Callers should not use the ICodeCompiler interface and should instead use the methods directly on the CodeDomProvider class.")] - public override ICodeCompiler CreateCompiler() { - return new VBCompiler(this, _compilerSettings); - } - } -} diff --git a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/packages.config b/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/packages.config deleted file mode 100644 index 163102c..0000000 --- a/src/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/packages.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites.nuproj b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites.nuproj new file mode 100644 index 0000000..2a02be6 --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites.nuproj @@ -0,0 +1,30 @@ + + + + + $(MSBuildProjectName) + $(MSBuildProjectName) + $(MSBuildProjectName).nuspec + false + + + + + + content\net472\web.config.install.xdt + + + content\net472\web.config.uninstall.xdt + + + tools + + + docs\Readme.md + + + icons + + + + \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites.nuspec b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites.nuspec new file mode 100644 index 0000000..dc9730c --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites.nuspec @@ -0,0 +1,29 @@ + + + + $NuGetPackageId$ + Codestin Search App + $NuGetPackageVersion$ + Microsoft + Microsoft + © Microsoft Corporation. All rights reserved. + An installer shim to get "Roslyn" CodeDOM providers included in project-less "Web Site" builds. + + This package was built from the source at $GitCommitLink$ + + WebSite Shim for CodeDOM providers that use the new .NET Compiler Platform ("Roslyn") compiler as a service APIs. + en-US + https://github.com/aspnet/RoslynCodeDomProvider + + icons\dotnet.png + docs\Readme.md + MIT + true + Roslyn CodeDOM Compiler CSharp VB.Net ASP.NET WebSite + + + + + + + \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Readme.md b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Readme.md new file mode 100644 index 0000000..5c2d56f --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/Readme.md @@ -0,0 +1,6 @@ +## Web Site integration for 4.X DotNetCompilerPlatform CodeDom Provider +This is a support package to enable proper integration of the 4.X series of the [Microsoft.CodeDom.Providers.DotNetCompilerPlatform](https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform) package with project-less "Web Sites." This package does not contain any libraries or providers of it's own. It simply restores the old 'install.ps1' nuget functionality to its tightly coupled 'DotNetCompilerPlatform' package dependency. Powershell installation was the only way to integrate with "Web Sites" which have very limited msbuild support. + +This package has an exact dependency on the _DotNetCompilerPlatform_ package of the same version. + +This package will fail to install on non-"Web Site" projects. diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/content/web.config.install.xdt similarity index 55% rename from src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.uninstall.xdt rename to src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/content/web.config.install.xdt index 5733481..8bdd7c4 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.uninstall.xdt +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/content/web.config.install.xdt @@ -1,5 +1,16 @@ + + + + + + + + + + + + + - - - - + \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/content/web.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/content/web.config.uninstall.xdt new file mode 100644 index 0000000..8dee510 --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/content/web.config.uninstall.xdt @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/common.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/common.ps1 new file mode 100644 index 0000000..0d74e30 --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/common.ps1 @@ -0,0 +1,254 @@ +# Copyright (c) .NET Foundation. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +## +## Assigning a "DefaultValue" to a ParameterDescription will result in emitting this parameter when +## writing out a default compiler declaration. +## +## Setting IsRequired to $true will require the attribute to be set on all declarations in config. +## +if ((-not ("CompilerParameterDescription" -as [type])) -or (-not ("CodeDomProviderDescription" -as [type]))) +{ + Add-Type @" + using System; + + public class CompilerParameterDescription { + public string Name; + public string DefaultValue; + public bool IsRequired; + public bool IsProviderOption; + } + + public class CodeDomProviderDescription { + public string TypeName; + public string Assembly; + public string Version; + public string FileExtension; + public CompilerParameterDescription[] Parameters; + } +"@ +} + +function InstallCodeDomProvider($providerDescription) { + ##### Update/Rehydrate config declarations ##### + $config = ReadConfigFile + $rehydratedCount = RehydrateOldDeclarations $config $providerDescription + $updatedCount = UpdateDeclarations $config $providerDescription + + ##### Add the default provider if it wasn't rehydrated above + $defaultProvider = $config.xml.configuration["system.codedom"].compilers.compiler | where { $_.extension -eq $providerDescription.FileExtension } + if ($defaultProvider -eq $null) { AddDefaultDeclaration $config $providerDescription } + SaveConfigFile $config | Out-Null +} + +function UninstallCodeDomProvider($providerType) { + ##### Dehydrate config declarations ##### + $config = ReadConfigFile + DehydrateDeclarations $config $providerType | Out-Null + SaveConfigFile $config | Out-Null +} + +function GetConfigFileName() { + # Try web.config first. Then fall back to app.config. + $configFile = $project.ProjectItems | where { $_.Name -ieq "web.config" } + if ($configFile -eq $null) { $configFile = $project.ProjectItems | where { $_.Name -ieq "app.config" } } + $configPath = $configFile.Properties | where { $_.Name -ieq "LocalPath" } + if ($configPath -eq $null) { $configPath = $configFile.Properties | where { $_.Name -ieq "FullPath" } } + return $configPath.Value +} + +function GetTempFileName() { + $uname = $project.UniqueName + if ([io.path]::IsPathRooted($uname)) { $uname = $project.Name } + return [io.path]::Combine($env:TEMP, "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Temp", $uname + ".xml") +} + +function ReadConfigFile() { + $configFile = GetConfigFileName + $configObj = @{ fileName = $configFile; xml = (Select-Xml -Path "$configFile" -XPath /).Node } + $configObj.xml.PreserveWhitespace = $true + return $configObj +} + +function DehydrateDeclarations($config, $typeName) { + $tempFile = GetTempFileName + $count = 0 + + if ([io.file]::Exists($tempFile)) { + $xml = (Select-Xml -Path "$tempFile" -XPath /).Node + $xml.PreserveWhitespace = $true + } else { + $xml = New-Object System.Xml.XmlDocument + $xml.PreserveWhitespace = $true + $xml.AppendChild($xml.CreateElement("driedDeclarations")) | Out-Null + } + + foreach ($rec in $config.xml.configuration["system.codedom"].compilers.compiler | where { IsSameType $_.type $typeName }) { + # Remove records from config. + $config.xml.configuration["system.codedom"].compilers.RemoveChild($rec) | Out-Null + + # Add the record to the temp stash. Don't worry about duplicates. + AppendChildNode $xml.ImportNode($rec, $true) $xml.DocumentElement | Out-Null + $count++ + } + + # Save the dehydrated declarations + $tmpFolder = Split-Path $tempFile + md -Force $tmpFolder | Out-Null + $xml.Save($tempFile) | Out-Null + return $count +} + +function RehydrateOldDeclarations($config, $providerDescription) { + $tempFile = GetTempFileName + if (![io.file]::Exists($tempFile)) { return 0 } + + $count = 0 + $xml = (Select-Xml -Path "$tempFile" -XPath /).Node + $xml.PreserveWhitespace = $true + + foreach($rec in $xml.driedDeclarations.compiler | where { IsSameType $_.type ($providerDescription.TypeName + "," + $providerDescription.Assembly) }) { + # Remove records that match type, even if we don't end up rehydrating them. + $xml.driedDeclarations.RemoveChild($rec) | Out-Null + + # Skip if an existing record of the same file extension already exists. + $existingRecord = $config.xml.configuration["system.codedom"].compilers.compiler | where { $_.extension -eq $rec.extension } + if ($existingRecord -ne $null) { continue } + + # Bring the record back to life + AppendChildNode $config.xml.ImportNode($rec, $true) $config.xml.configuration["system.codedom"]["compilers"] | Out-Null + $count++ + Write-Host "Restored system.codedom compiler for extension '$($rec.extension)'." + } + + # Make dried record removal permanent + $xml.Save($tempFile) | Out-Null + + return $count +} + +function UpdateDeclarations($config, $providerDescription) { + $count = 0 + + foreach ($provider in $config.xml.configuration["system.codedom"].compilers.compiler | where { IsSameType $_.type ($providerDescription.TypeName + "," + $providerDescription.Assembly) }) { + + $failed = $false + + # Add default attributes if they are required and not already present + foreach ($p in $providerDescription.Parameters | where { ($_.IsRequired -eq $true) -and ($_.IsProviderOption -eq $false) }) { + if ($provider.($p.Name) -eq $null) { + if ($p.DefaultValue -eq $null) { + Write-Warning "Failed to add parameter to '$($provider.name)' codeDom provider: '$($p.Name)' is required, but does not have a default value." + $failed = $true + } + $attr = $config.xml.CreateAttribute($p.Name) + $attr.Value = $p.DefaultValue + $provider.Attributes.InsertBefore($attr, $provider.Attributes["type"]) | Out-Null + } + } + + # Do the same thing for default providerOptions if not already present + foreach ($p in $providerDescription.Parameters | where { ($_.IsRequired -eq $true) -and ($_.IsProviderOption -eq $true)}) { + $existing = $provider.providerOption | where { $_.name -eq $p.Name } + if ($existing -eq $null) { + if ($p.DefaultValue -eq $null) { + Write-Warning "Failed to add providerOption to '$($provider.name)' codeDom provider: '$($p.Name)' is required, but does not have a default value." + $failed = $true + } + $po = $config.xml.CreateElement("providerOption") + $po.SetAttribute("name", $p.Name) | Out-Null + $po.SetAttribute("value", $p.DefaultValue) | Out-Null + AppendChildNode $po $provider 4 | Out-Null + } + } + + # Finally, update type. And do so with remove/add so the 'type' parameter gets put at the end + $provider.RemoveAttribute("type") | Out-Null + $provider.SetAttribute("type", "$($providerDescription.TypeName), $($providerDescription.Assembly), Version=$($providerDescription.Version), Culture=neutral, PublicKeyToken=31bf3856ad364e35") | Out-Null + + if ($failed -ne $true) { $count++ } + } + + return $count +} + +function AddDefaultDeclaration($config, $providerDescription) { + $dd = $config.xml.CreateElement("compiler") + + # file extension first + $dd.SetAttribute("extension", $providerDescription.FileExtension) | Out-Null + + # everything else in the middle + foreach ($p in $providerDescription.Parameters) { + if ($p.IsRequired -and ($p.DefaultValue -eq $null)) { + Write-Host "Failed to add default declaration for code dom extension '$($providerDescription.FileExtension)': '$($p.Name)' is required, but does not have a default value." + return + } + + if ($p.DefaultValue -ne $null) { + if ($p.IsProviderOption -eq $true) { + $po = $config.xml.CreateElement("providerOption") + $po.SetAttribute("name", $p.Name) | Out-Null + $po.SetAttribute("value", $p.DefaultValue) | Out-Null + AppendChildNode $po $dd 4 | Out-Null + } else { + $dd.SetAttribute($p.Name, $p.DefaultValue) | Out-Null + } + } + } + + # type last + $dd.SetAttribute("type", "$($providerDescription.TypeName), $($providerDescription.Assembly), Version=$($providerDescription.Version), Culture=neutral, PublicKeyToken=31bf3856ad364e35") | Out-Null + + AppendChildNode $dd $config.xml.configuration["system.codedom"]["compilers"] | Out-Null + Write-Host "Added system.codedom compiler for extension '$($dd.extension)'." +} + +function AppendChildNode($provider, $parent, $indentLevel = 3) { + $lastSibling = $parent.ChildNodes | where { $_ -isnot [System.Xml.XmlWhitespace] } | select -Last 1 + if ($lastSibling -ne $null) { + # If not the first child, then copy the whitespace convention of the existing child + $ws = ""; + $prev = $lastSibling.PreviousSibling | where { $_ -is [System.Xml.XmlWhitespace] } + while ($prev -ne $null) { + $ws = $prev.data + $ws + $prev = $prev.PreviousSibling | where { $_ -is [System.Xml.XmlWhitespace] } + } + $parent.InsertAfter($provider, $lastSibling) | Out-Null + if ($ws.length -gt 0) { $parent.InsertAfter($parent.OwnerDocument.CreateWhitespace($ws), $lastSibling) | Out-Null } + return + } + + # Add on a new line with indents. Make sure there is no existing whitespace mucking this up. + foreach ($exws in $parent.ChildNodes | where { $_ -is [System.Xml.XmlWhitespace] }) { $parent.RemoveChild($exws) | Out-Null } + $parent.AppendChild($parent.OwnerDocument.CreateWhitespace("`r`n")) | Out-Null + $parent.AppendChild($parent.OwnerDocument.CreateWhitespace(" " * $indentLevel)) | Out-Null + $parent.AppendChild($provider) | Out-Null + $parent.AppendChild($parent.OwnerDocument.CreateWhitespace("`r`n")) | Out-Null + $parent.AppendChild($parent.OwnerDocument.CreateWhitespace(" " * ($indentLevel - 1))) | Out-Null +} + +function SaveConfigFile($config) { + $config.xml.Save($config.fileName) | Out-Null +} + +function IsSameType($typeString1, $typeString2) { + + if (($typeString1 -eq $null) -or ($typeString2 -eq $null)) { return $false } + + # First check the type + $t1 = $typeString1.Split(',')[0].Trim() + $t2 = $typeString2.Split(',')[0].Trim() + if ($t1 -cne $t2) { return $false } + + # Then check for assembly match if possible + $a1 = $typeString1.Split(',')[1] + $a2 = $typeString2.Split(',')[1] + if (($a1 -ne $null) -and ($a2 -ne $null)) { + return ($a1.Trim() -eq $a2.Trim()) + } + + # Don't care about assembly. Match is good. + return $true +} diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/install.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/install.ps1 new file mode 100644 index 0000000..27c8c9e --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/install.ps1 @@ -0,0 +1,96 @@ +# Copyright (c) .NET Foundation. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + +###################################################################################################### +## The main MS.CD.Providers.DotNetCompilerPlatform package uses targets files to do all this work ## +## at build time. WebSite 'projects' can't take advantage of msbuild/targets files, so this package ## +## brings back the install.ps1 functionality that shoehorns bits into WebSite builds. ## +###################################################################################################### + +param($installPath, $toolsPath, $package, $project) + +$assemblyVersion = '4.1.0.0' + +if ($project -eq $null) { + $project = Get-Project +} + +# This package is only for WebSite "projects." +# Fail noisily if trying to install on any other project type. +if ($project.Type -ne 'Web Site') +{ + throw "This package is intended only for 'Web Site' projects. Aborting install." +} + +$compilerVersion = $package.Version +if($package.Versions -ne $null) { $compilerVersion = @($package.Versions)[0] } +$projectRoot = $project.Properties.Item('FullPath').Value +$binDirectory = Join-Path $projectRoot 'bin' +$roslynSubFolder = 'roslyn' +$packageDirectory = Split-Path $installPath +$compilerPackageName = "Microsoft.CodeDom.Providers.DotNetCompilerPlatform." + $compilerVersion +$compilerPackageDirectory = Join-Path $packageDirectory $compilerPackageName +$providerBits = Join-Path $compilerPackageDirectory "lib\net472" +$roslynBits = Join-Path $compilerPackageDirectory "tools\Roslyn-$compilerVersion" +$csLanguageVersion = '7.3' +$vbLanguageVersion = 'default' + +# Check for existence of the roslyn codedom provider package before continuing +if ((Get-Item $compilerPackageDirectory) -isnot [System.IO.DirectoryInfo]) +{ + throw "The install.ps1 cannot find the installation location of package $compilerPackageName, or the pakcage is not installed correctly." +} + +# Fill out the config entries for these code dom providers here. Using powershell to do +# this allows us to cache and restore customized attribute values from previous versions of +# this package in the upgrade scenario. +. "$PSScriptRoot\common.ps1" +$csCodeDomProvider = [CodeDomProviderDescription]@{ + TypeName="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider"; + Assembly="Microsoft.CodeDom.Providers.DotNetCompilerPlatform"; + Version=$assemblyVersion; + FileExtension=".cs"; + Parameters=@( + [CompilerParameterDescription]@{ Name="language"; DefaultValue="c#;cs;csharp"; IsRequired=$true; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="warningLevel"; DefaultValue="4"; IsRequired=$true; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="compilerOptions"; DefaultValue="/langversion:" + $csLanguageVersion + " /nowarn:1659;1699;1701;612;618"; IsRequired=$false; IsProviderOption=$false }); +} +InstallCodeDomProvider $csCodeDomProvider +$vbCodeDomProvider = [CodeDomProviderDescription]@{ + TypeName="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider"; + Assembly="Microsoft.CodeDom.Providers.DotNetCompilerPlatform"; + Version=$assemblyVersion; + FileExtension=".vb"; + Parameters=@( + [CompilerParameterDescription]@{ Name="language"; DefaultValue="vb;vbs;visualbasic;vbscript"; IsRequired=$true; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="warningLevel"; DefaultValue="4"; IsRequired=$true; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="compilerOptions"; DefaultValue="/langversion:" + $vbLanguageVersion + " /nowarn:41008,40000,40008 /define:_MYTYPE=\""Web\"" /optionInfer+"; IsRequired=$false; IsProviderOption=$false }); +} +InstallCodeDomProvider $vbCodeDomProvider + +# We need to copy the provider assembly into the bin\ folder, otherwise +# Microsoft.VisualStudio.Web.Host.exe cannot find the assembly. +# However, users will see the error after they clean solutions. +New-Item $binDirectory -type directory -force | Out-Null +Copy-Item $providerBits\* $binDirectory -force | Out-Null + +# Copy the Roslyn toolset into the website's bin folder as well. +$roslynSubDirectory = Join-Path $binDirectory $roslynSubFolder +New-Item $roslynSubDirectory -type directory -force | Out-Null +Copy-Item $roslynBits\* $roslynSubDirectory -force | Out-Null + +# Generate a .refresh file for each dll/exe file. +Push-Location +Set-Location $projectRoot +$relativeAssemblySource = Resolve-Path -relative $roslynBits +Pop-Location + +Get-ChildItem -Path $roslynSubDirectory | ` +Foreach-Object { + if (($_.Extension -eq ".dll") -or ($_.Extension -eq ".exe")) { + $refreshFile = $_.FullName + $refreshFile += ".refresh" + $refreshContent = Join-Path $relativeAssemblySource $_.Name + Set-Content $refreshFile $refreshContent + } +} \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/uninstall.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/uninstall.ps1 new file mode 100644 index 0000000..55a8745 --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites/tools/uninstall.ps1 @@ -0,0 +1,37 @@ +# Copyright (c) .NET Foundation. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + +###################################################################################################### +## The main MS.CD.Providers.DotNetCompilerPlatform package uses targets files to do all this work ## +## at build time. WebSite 'projects' can't take advantage of msbuild/targets files, so this package ## +## brings back the install.ps1 functionality that shoehorns bits into WebSite builds. ## +###################################################################################################### + +param($installPath, $toolsPath, $package, $project) + +# This package is only for WebSite "projects" +if ($project.Type -eq 'Web Site') { + + # First save the code dom compiler declarations off to a temp file so they can be restored + # in the event that this is a package upgrade scenario. + . "$PSScriptRoot\common.ps1" + UninstallCodeDomProvider "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform" + UninstallCodeDomProvider "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform" + + + # Then remove the compiler bits from the bin directory + $roslynSubFolder = 'roslyn' + + if ($project -eq $null) { + $project = Get-Project + } + + $projectRoot = $project.Properties.Item('FullPath').Value + $binDirectory = Join-Path $projectRoot 'bin' + $targetDirectory = Join-Path $binDirectory $roslynSubFolder + + if (Test-Path $targetDirectory) { + Get-Process -Name "VBCSCompiler" -ErrorAction SilentlyContinue | Stop-Process -Force -PassThru -ErrorAction SilentlyContinue | Wait-Process + Remove-Item $targetDirectory -Force -Recurse -ErrorAction SilentlyContinue + } +} \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj index 9d50b90..987e7e5 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj @@ -1,37 +1,52 @@ - - - $(MSBuildProjectName) - $(MSBuildProjectName) - $(MSBuildProjectName).nuspec - - - - $(AssemblyPath) - lib\net45 - - - $(OutputPath) - lib\net45 - - - $(OutputPath) - lib\net45 - - - - content\net45 - - - content\net46 - - - build\net45 - - - tools\net45 - - - + + + $(MSBuildProjectName) + $(MSBuildProjectName) + $(MSBuildProjectName).nuspec + + + + + + + + + + + $(AssemblyPath) + lib\net472 + + + $(OutputPath) + lib\net472 + + + $(OutputPath) + lib\net472 + + + + $(OutputPath) + tasks + + + $(OutputPath) + tasks + + + build\net472 + + + tools\$(LocalRoslynFolderName) + + + docs\Readme.md + + + icons + + + \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuspec b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuspec index 031b782..e1d2aa7 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuspec +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuspec @@ -1,5 +1,5 @@  - + $NuGetPackageId$ Codestin Search App @@ -7,20 +7,18 @@ Microsoft Microsoft © Microsoft Corporation. All rights reserved. - Replacement CodeDOM providers that use the new .NET Compiler Platform ("Roslyn") compiler as a service APIs. This provides support for new language features in systems using CodeDOM (e.g. ASP.NET runtime compilation) as well as improving the compilation performance of these systems. + Replacement CodeDOM providers that use the new .NET Compiler Platform ("Roslyn") compiler as a service APIs. This provides support for new language features in systems using CodeDOM (e.g. ASP.NET runtime compilation) as well as improving the compilation performance of these systems. + + This package was built from the source at $GitCommitLink$ + Replacement CodeDOM providers that use the new .NET Compiler Platform ("Roslyn") compiler as a service APIs. en-US - http://www.asp.net/ - http://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm + https://github.com/aspnet/RoslynCodeDomProvider + + icons\dotnet.png + docs\Readme.md + MIT true Roslyn CodeDOM Compiler CSharp VB.Net ASP.NET - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Readme.md b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Readme.md new file mode 100644 index 0000000..8b3d001 --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Readme.md @@ -0,0 +1,32 @@ +## :warning: Project-less 'WebSite's should use [....DotNetCompilerPlatform.WebSites](https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites) package :warning: +Version 4.X of this package has moved fully into an msbuild/targets model. But "Web Site"s - because they are "project-less" - have very limited support in msbuild and the package does not fully install like it did in the 3.X and earlier releases. Please use the [Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites](https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites) package for proper integration with a "Web Site" project. + +## Introduction +Replacement CodeDOM providers that use the new .NET Compiler Platform ("Roslyn") compiler as a service APIs. This provides support for new language features in systems using CodeDOM (e.g. ASP.NET runtime compilation) as well as improving the compilation performance of these systems. + +Please see the blog [Enabling the .NET Compiler Platform (“Roslyn”) in ASP.NET applications](https://blogs.msdn.microsoft.com/webdev/2014/05/12/enabling-the-net-compiler-platform-roslyn-in-asp-net-applications/) +for an introduction to Microsoft.CodeDom.Providers.DotNetCompilerPlatform. The [project github](https://github.com/aspnet/RoslynCodeDomProvider) also has the most up-to-date documentation of the various settings available for configuring this provider. + +## Updates ++ #### Version 4.5.0 + - #### Refreshed compilers + In keeping with the new versioning scheme for this project, the version has been revved to 4.5 to match the version of the compilers included. + + :information_source: The source of compiler tools in this package has been updated to [Microsoft.Net.Compilers.**Toolset**](https://www.nuget.org/packages/Microsoft.Net.Compilers.Toolset) from the old, deprecated `Microsoft.Net.Compilers` package that had been used before. There shouldn't be any behavioral change due to this change in Roslyn packages. + + - #### Fixed targets-based tool copy + The msbuild targets-based identification and copy of Roslyn files to the project output was not working correctly in the last version. This has been fixed to ensure that Roslyn compiler files are copied to the correct location during build. + ++ #### Version 4.1.0 (preview1) + - #### Drop install.ps1, Rely more on msbuild + Nuget has moved on from install.ps1. We had one foot in the msbuild camp before, and one foot still in the install.ps1 camp. Time to just jump in with both feet. See the 'RoslynRegisterInConfig' setting description below. + + - #### Refreshed current compilers + In keeping with the new versioning scheme for this project, the version has been revved to 4.1 to match the version of the compilers included. + + - #### No more old compilers + Stop carrying old versions of compilers. If you upgrade to get new compilers, you get new compilers. The old compilers that might carry references to binaries that get flagged in security scans even though the binaries don't get copied to the ouput directory... they just won't be included in the package anymore. + + - #### .Net >= 4.7.2 + As a result of not keeping older compilers packaged in this project, we can no longer support versions before 4.7.2 because compiler versions 3.0 and newer only support 4.7.2+. + diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/build/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/build/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props deleted file mode 100644 index 7443672..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/build/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props +++ /dev/null @@ -1,67 +0,0 @@ - - - - roslyn\%(RecursiveDir)%(Filename)%(Extension) - - - - - - bin\roslyn\%(RecursiveDir)%(Filename)%(Extension) - IncludeRoslynCompilerFilesToFilesForPackagingFromProject - Run - - - - - - - - - - - - - - - - - - - - - - - - ().FirstOrDefault(); - Log.LogMessage("ExecutablePath is {0}", (string)mo["ExecutablePath"]); - if(mo != null && string.Compare((string)mo["ExecutablePath"], ImagePath, StringComparison.OrdinalIgnoreCase) > 0) - { - p.Kill(); - Log.LogMessage("{0} is killed", (string)mo["ExecutablePath"]); - break; - } - } - } - } - } - catch (Exception ex) - { - Log.LogErrorFromException(ex); - } - return true; - ]]> - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/build/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.targets b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/build/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.targets new file mode 100644 index 0000000..72e11b3 --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/build/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.targets @@ -0,0 +1,80 @@ + + + + true + true + $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\$roslynToolPath$')) + + + + + + <_RoslynCompilerFilesList Include='$(RoslynToolPath)\**\*' /> + + + + + + + + bin\roslyn\%(RecursiveDir)%(Filename)%(Extension) + roslyn\%(RecursiveDir)%(Filename)%(Extension) + IncludeRoslynCompilerFilesToFilesForPackagingFromProject + Run + + + + + + + + + $(WebProjectOutputDir)\bin\roslyn + $(OutDir)\roslyn + $(OutputPath)\roslyn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.install.xdt deleted file mode 100644 index 0b7bc6d..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.install.xdt +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.install.xdt deleted file mode 100644 index 8f95055..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.install.xdt +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.uninstall.xdt deleted file mode 100644 index 5733481..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.uninstall.xdt +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/install.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/install.ps1 deleted file mode 100644 index 47bf983..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/install.ps1 +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) .NET Foundation. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for full license information. - -param($installPath, $toolsPath, $package, $project) - -$compilerPackageName = 'Microsoft.Net.Compilers' -$roslynSubFolder = 'roslyn' - -if ($project -eq $null) { - $project = Get-Project -} - -$libDirectory = Join-Path $installPath 'lib\net45' -$projectRoot = $project.Properties.Item('FullPath').Value -$binDirectory = Join-Path $projectRoot 'bin' - -# We need to copy the provider assembly into the bin\ folder, otherwise -# Microsoft.VisualStudio.Web.Host.exe cannot find the assembly. -# However, users will see the error after they clean solutions. -New-Item $binDirectory -type directory -force | Out-Null -Copy-Item $libDirectory\* $binDirectory -force | Out-Null - -# For Web Site, we need to copy the Roslyn toolset into -# the applicaiton's bin folder. -# For Web Applicaiton project, this is done in csproj. -if ($project.Type -eq 'Web Site') { - $packageDirectory = Split-Path $installPath - - # Get the installed Microsoft.Net.Compilers package. - $compilerPackage = Get-Package -ProjectName $project.Name | Where-Object {$_.Id -eq $compilerPackageName} - if ($compilerPackage -eq $null) - { - Write-Host "Package $compilerPackageName is not installed correctly." - Write-Host 'The install.ps1 did not complete.' - break - } - - if($compilerPackage.Versions -eq $null) - { - $compilerVersion = $compilerPackage.Version - } - else - { - $compilerVersion = @($compilerPackage.Versions)[0] - } - - $compilerPackageFolderName = $compilerPackage.Id + "." + $compilerVersion - $compilerPackageDirectory = Join-Path $packageDirectory $compilerPackageFolderName - if ((Get-Item $compilerPackageDirectory) -isnot [System.IO.DirectoryInfo]) - { - Write-Host "The install.ps1 cannot find the installation location of package $compilerPackageName, or the pakcage is not installed correctly." - Write-Host 'The install.ps1 did not complete.' - break - } - - $compilerPackageToolsDirectory = Join-Path $compilerPackageDirectory 'tools' - $roslynSubDirectory = Join-Path $binDirectory $roslynSubFolder - New-Item $roslynSubDirectory -type directory -force | Out-Null - Copy-Item $compilerPackageToolsDirectory\* $roslynSubDirectory -force | Out-Null - - # Generate a .refresh file for each dll/exe file. - Push-Location - Set-Location $projectRoot - $relativeAssemblySource = Resolve-Path -relative $compilerPackageToolsDirectory - Pop-Location - - Get-ChildItem -Path $roslynSubDirectory | ` - Foreach-Object { - if (($_.Extension -eq ".dll") -or ($_.Extension -eq ".exe")) { - $refreshFile = $_.FullName - $refreshFile += ".refresh" - $refreshContent = Join-Path $relativeAssemblySource $_.Name - Set-Content $refreshFile $refreshContent - } - } -} \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/uninstall.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/uninstall.ps1 deleted file mode 100644 index e6efdda..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/uninstall.ps1 +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) .NET Foundation. All rights reserved. -# Licensed under the MIT license. See LICENSE file in the project root for full license information. - -param($installPath, $toolsPath, $package, $project) - -$roslynSubFolder = 'roslyn' - -if ($project -eq $null) { - $project = Get-Project -} - -$projectRoot = $project.Properties.Item('FullPath').Value -$binDirectory = Join-Path $projectRoot 'bin' -$targetDirectory = Join-Path $binDirectory $roslynSubFolder - -if (Test-Path $targetDirectory) { - Remove-Item $targetDirectory -Force -Recurse -} \ No newline at end of file diff --git a/src/Packages/Packages.csproj b/src/Packages/Packages.csproj index 77cbf90..27372d7 100644 --- a/src/Packages/Packages.csproj +++ b/src/Packages/Packages.csproj @@ -1,5 +1,5 @@  - + Release @@ -12,13 +12,33 @@ SAK SAK SAK + v4.7.2 + false + false - - + + false + + + + + + + + + + + + + + + + + diff --git a/src/Packages/icons/dotnet.png b/src/Packages/icons/dotnet.png new file mode 100644 index 0000000..a3b74d1 Binary files /dev/null and b/src/Packages/icons/dotnet.png differ diff --git a/tools/.verif.whitelist b/tools/.verif.whitelist new file mode 100644 index 0000000..039b71e --- /dev/null +++ b/tools/.verif.whitelist @@ -0,0 +1 @@ +*\lib\*\*.xml,ignore xmldoc files \ No newline at end of file diff --git a/tools/NuGet.targets b/tools/NuGet.targets index f943812..eba37eb 100644 --- a/tools/NuGet.targets +++ b/tools/NuGet.targets @@ -58,7 +58,7 @@ -RequireConsent -NonInteractive - "$(SolutionDir) " + "$(SolutionDir)" "$(SolutionDir)" diff --git a/tools/NuGetProj.targets b/tools/NuGetProj.targets index 70e9d99..1d8208c 100644 --- a/tools/NuGetProj.targets +++ b/tools/NuGetProj.targets @@ -184,7 +184,11 @@ Common build targets overwrites. Clean;Build - + + + + + @@ -269,7 +273,7 @@ NuGetPack: Creates a nuget package. @(NuSpecProperties) -NoPackageAnalysis - -NoPackageAnalysis -symbols + -NoPackageAnalysis -Symbols -SymbolPackageFormat snupkg $(BuildCommand.Replace('-symbols', '')) $(BuildCommand.Replace('/symbols', '')) @@ -304,10 +308,11 @@ GetNuGetProjectOutputs: Reads build-generated files from outputs file. $(PackageOutputDir)\$(NuGetPackageId).$(NuGetPackageVersion).nupkg - $(PackageOutputDir)\$(NuGetPackageId).$(NuGetPackageVersion).symbols.nupkg + $(PackageOutputDir)\$(NuGetPackageId).$(NuGetPackageVersion).symbols.nupkg + diff --git a/tools/RoslynCodeProvider.Extensions.targets b/tools/RoslynCodeProvider.Extensions.targets index fdcb4a4..35c5ce9 100644 --- a/tools/RoslynCodeProvider.Extensions.targets +++ b/tools/RoslynCodeProvider.Extensions.targets @@ -1,18 +1,100 @@ - - - - - $(NuGetPackageVersion)-b$(VersionBuild) + + + $(RepositoryRoot)src\Packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform\tools\ + Roslyn-$(MSNetCompilersNuGetPackageVersion) - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + properties = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); // Nuget .pp transforms are case insensitive + foreach (var p in PropertyCollection) { properties.TryAdd(p.GetMetadata("Identity"), p.GetMetadata("Value")); } + foreach (var inFile in Files) { + string filename = inFile.ItemSpec; + if (!File.Exists(filename)) { Log.LogError("File to preprocess does not exist: {0}", filename); return false; } + if (!Directory.Exists(OutputDir)) { Directory.CreateDirectory(OutputDir); } + using (StreamReader sr = new StreamReader(filename)) + using (StreamWriter sw = new StreamWriter(Path.Combine(OutputDir, Path.GetFileName(filename)), false)) + { + while ((line = sr.ReadLine()) != null) { + line = Regex.Replace(line, tokenPattern, (m) => { + string key = m.Groups[1].Value; + if (properties.ContainsKey(key)) { return properties[key]; } + return m.Groups[0].Value; + }); + sw.WriteLine(line); + } + } + } + ]]> + + + diff --git a/tools/RoslynCodeProvider.settings.targets b/tools/RoslynCodeProvider.settings.targets index 431bc47..3634420 100644 --- a/tools/RoslynCodeProvider.settings.targets +++ b/tools/RoslynCodeProvider.settings.targets @@ -1,47 +1,125 @@ - - + - - rtm - 2014 - 1 - 0 - 7 - $(VersionRelease)-$(BuildQuality) - + + + + + preview1 + 2025 + 4 + 5 + 0 + 0 + 0 + - + + 4.5.0 + - - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), RoslynCodeProvider.sln))\ - + + + $(MSBuildThisFileDirectory)version.targets;$(MSBuildThisFileDirectory)signing.targets + $(MSBuildThisFileDirectory)signing.targets + $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), RoslynCodeProvider.sln))\ + $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), RoslynCodeProvider.sln))\ + - - Release - $(RepositoryRoot)bin\$(Configuration)\ - $(RepositoryRoot)obj\$(Configuration)\$(MSBuildProjectName)\ - + - - $(OutputPath) - $(AssemblyPath)Packages - $(AssemblyPath)\SymbolPackages - $(OutputPath)test\ - + + - - $(RepositoryRoot)packages\ - true - $(RepositoryRoot)\src\$(MSBuildProjectName)\ - + + + + + + + + + Release + $(RepositoryRoot).binaries\bin\$(Configuration)\ + $(RepositoryRoot).binaries\obj\$(Configuration)\$(MSBuildProjectName)\ + $(CodeSignOutputPath) + $(OutputPath) + $(OutputPath)test\ + + + + + $(RepositoryRoot).binaries\Packages\$(Configuration) + true + $(RepositoryRoot)packages\ + $(RepositoryRoot)\src\$(MSBuildProjectName)\ + $(MSBuildProjectDirectory)\tools + $(MSBuildProjectDirectory)\build + pp + + + + + + + + + - $(RepositoryRoot)tools\RoslynCodeProvider.targets - $(CustomAfterMicrosoftCommonTargets) + + NuGetPackageVersion=$(NuGetPackageVersion); + NuGetPackageId=$(NuGetPackageId); + GitCommitLink=$(GitCommitLink); + + + + + + + tools\roslyn-$(MSNetCompilersNuGetPackageVersion) + + + Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=$(AssemblyVersion), Culture=neutral, PublicKeyToken=31bf3856ad364e35 + + + $(AssemblyVersion) + + + + + + + + + + + $(RepositoryRoot)\RoslynCodeProviderTest + true + + + + + + + + + + + + + + + diff --git a/tools/RoslynCodeProvider.targets b/tools/RoslynCodeProvider.targets deleted file mode 100644 index 7d5c7bb..0000000 --- a/tools/RoslynCodeProvider.targets +++ /dev/null @@ -1,30 +0,0 @@ - - - - - SetNuSpecProperties;$(BuildDependsOn) - - - - - - - - $(AssemblyVersion) - - - - - - - - - - NuGetPackageVersion=$(NuGetPackageVersion); - NuGetPackageId=$(NuGetPackageId); - MSNetCompilersNuGetPackageVersion=$(MSNetCompilersNuGetPackageVersion); - MSNetCompilersNuGetPackageLatestVersion=$(MSNetCompilersNuGetPackageLatestVersion) - - - - diff --git a/tools/signing.targets b/tools/signing.targets new file mode 100644 index 0000000..a4038c6 --- /dev/null +++ b/tools/signing.targets @@ -0,0 +1,40 @@ + + + + + + + Microsoft400 + MsSharedLib72 + + + + + + + + + Microsoft400 + + + Microsoft400 + + + + + + + + + $(PackageOutputDir) + + + + NuGet + + + + + \ No newline at end of file diff --git a/tools/version.targets b/tools/version.targets index 9a8b3d4..588bcf0 100644 --- a/tools/version.targets +++ b/tools/version.targets @@ -9,33 +9,49 @@ Project global versioning targets. - true false + - 2013 + <_PreventVSPropertyCaching>$([System.DateTime]::Now.Ticks) + INVALID_VersionStartYear INVALID_VersionMajor INVALID_VersionMinor - $([MSBuild]::Add(1, $([MSBuild]::Subtract($([System.DateTime]::Now.Year), $(VersionStartYear)))))$([System.DateTime]::Now.ToString("MMdd")) 0 0 + 0 + $([MSBuild]::Add(1, $([MSBuild]::Subtract($([System.DateTime]::Now.Year), $(VersionStartYear)))))$([System.DateTime]::Now.ToString("MMdd")) - $(VersionMajor).$(VersionMinor).$(VersionRelease).$(VersionRevision) - $(VersionMajor).$(VersionMinor).$(VersionBuild).$(VersionRevision) - $(VersionMajor).$(VersionMinor).$(VersionRelease)-$(VersionBuild) - $(AssemblyFileVersion) + <_PreventVSPropertyCaching2>$([System.DateTime]::Now.Ticks) + $(VersionMajor).$(VersionMinor).$(VersionRevision).$(VersionBuild) + $(VersionMajor).$(VersionMinor).$(VersionRevision).$(VersionBuild) + $(VersionMajor).$(VersionMinor).$(VersionRelease)-$(VersionBuild) $(IntermediateOutputPath)$(MSBuildProjectName).version.cs + $(AssemblyVersion) + $(VersionMajor).$(VersionMinor).$(VersionRelease) - - $(VersionMajor).$(VersionMinor).$(VersionRelease) + + $(NuGetPackageVersion)-$(BuildQuality) + + + $(NuGetPackageVersion)$(VersionBuild) @@ -67,7 +83,22 @@ Project global versioning targets. - + + + + + + + $(GitDescribeOutput) + + + + + + $(VersionMajor).$(VersionMinor).$(VersionRelease)+$(GitCommit) + $(VersionMajor).$(VersionMinor).$(VersionRelease)-$(VersionBuild) + $(AssemblyFileVersion) + @@ -104,7 +135,7 @@ Project global versioning targets. $([System.Convert]::ToInt16('$(VersionMajor)')) $([System.Convert]::ToInt16('$(VersionMinor)')) - $([System.Convert]::ToInt32('$(VersionBuild)')) + $([System.Convert]::ToInt16('$(VersionBuild)')) $([System.Convert]::ToInt16('$(VersionRevision)'))