Skip to content

Commit

Permalink
V4 fork (aspnet#148)
Browse files Browse the repository at this point in the history
* Big V4 Update. PS1/XDT ==> MSBuild migration.

* Fix preview versioning.

* Rev to 4.1-rtm
  • Loading branch information
StephenMolloy authored Apr 12, 2023
1 parent 6b67ad9 commit 919235a
Show file tree
Hide file tree
Showing 16 changed files with 251 additions and 570 deletions.
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ Please see the blog [Enabling the .NET Compiler Platform (“Roslyn”) in ASP.N
for an introduction to Microsoft.CodeDom.Providers.DotNetCompilerPlatform.

## Updates
+ #### Version 4.1.0 (preview1)
- #### 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+.

- #### 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.

+ #### Version 3.11.0 (preview1)
- #### 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.
Expand Down Expand Up @@ -46,13 +59,28 @@ for an introduction to Microsoft.CodeDom.Providers.DotNetCompilerPlatform.
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
+ **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.
+ **(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.

**Setting name** - RoslynToolPath

**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.

+ **(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.

**Setting name** - RoslynCopyToOutDir

**How to use it** - ```msbuild mysolution.sln /t:build /p:RoslynCopyToOutDir="[true|false]"```

+ **(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.

**Setting name** - RoslynRegisterInConfig

**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
+ **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.

Expand Down
4 changes: 2 additions & 2 deletions RoslynCodeProviderTest/CommonCodeDomProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public void AssemblyVersion(CodeDomProvider provider)
{
var ver = provider.GetType().Assembly.GetName().Version;

Assert.Equal(3, ver.Major);
Assert.Equal(11, ver.Minor);
Assert.Equal(4, ver.Major);
Assert.Equal(1, ver.Minor);
}

public void FileExtension(CodeDomProvider provider, string extension) {
Expand Down
114 changes: 114 additions & 0 deletions src/DotNetCompilerPlatformTasks/UpdateCompilerConfigRecord.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
<ItemGroup>
<NuGetContent Include="$(AssemblyName).dll">
<Source>$(AssemblyPath)</Source>
<Destination>lib\net462</Destination>
<Destination>lib\net472</Destination>
</NuGetContent>
<NuGetContent Include="$(AssemblyName).xml">
<Source>$(OutputPath)</Source>
<Destination>lib\net462</Destination>
<Destination>lib\net472</Destination>
</NuGetContent>
<NuGetContent Include="$(AssemblyName).pdb" Condition="'$(NuGetPackSymbols)' == 'true'">
<Source>$(OutputPath)</Source>
<Destination>lib\net462</Destination>
<Destination>lib\net472</Destination>
</NuGetContent>
<NuGetContentProject Include="$(RepositoryRoot)\src\$(MSBuildProjectName)\$(MSBuildProjectName).csproj" Condition="'$(NuGetPackSymbols)' == 'true'" />
<NuGetContent Include="DotNetCompilerPlatformTasks.dll">
Expand All @@ -29,72 +29,17 @@
<Source>$(OutputPath)</Source>
<Destination>tasks</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.install.xdt">
<Destination>content\net462\app.config.install.xdt</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.install.xdt">
<Destination>content\net462\web.config.install.xdt</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.uninstall.xdt">
<Destination>content\net462\app.config.uninstall.xdt</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.uninstall.xdt">
<Destination>content\net462\web.config.uninstall.xdt</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.install.xdt">
<Destination>content\net472\app.config.install.xdt</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.install.xdt">
<Destination>content\net472\web.config.install.xdt</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.uninstall.xdt">
<Destination>content\net472\app.config.uninstall.xdt</Destination>
</NuGetContent>
<NuGetContent Include="Content\config.uninstall.xdt">
<Destination>content\net472\web.config.uninstall.xdt</Destination>
</NuGetContent>
<NuGetContent Include="build\*">
<Destination>build\net472</Destination>
</NuGetContent>
<NuGetContent Include="build\*">
<Destination>build\net462</Destination>
</NuGetContent>
<NuGetContent Include="build\net46\*">
<Destination>build\net462</Destination>
</NuGetContent>
<NuGetContent Include="build\net472\*">
<NuGetContent Include="build.pp\*">
<Destination>build\net472</Destination>
</NuGetContent>
<NuGetContent Include="tools\*.ps1" Condition="'$(SignAssembly)' != 'true'">
<Destination>tools</Destination>
</NuGetContent>
<NuGetContent Include="tools\signed\*.ps1" Condition="'$(SignAssembly)' == 'true'">
<Destination>tools</Destination>
</NuGetContent>
<NuGetContent Include="tools\$(LocalRoslyn46FolderName)\*">
<Destination>tools\$(LocalRoslyn46FolderName)</Destination>
</NuGetContent>
<NuGetContent Include="tools\$(LocalRoslyn472FolderName)\*">
<Destination>tools\$(LocalRoslyn472FolderName)</Destination>
<NuGetContent Include="tools\$(LocalRoslynFolderName)\*">
<Destination>tools\$(LocalRoslynFolderName)</Destination>
</NuGetContent>
<NuGetContent Include="..\icons\*">
<Destination>icons</Destination>
</NuGetContent>
</ItemGroup>
<Import Project="$(RepositoryRoot)Tools\NuGetProj.targets"/>
<Target Name="SignPowerShellScript" Condition=" '$(SignAssembly)' == 'true' " AfterTargets="BeforeBuild">
<ItemGroup>
<OriginalScriptFiles Include="$(MSBuildThisFileDirectory)\tools\*.ps1" />
</ItemGroup>
<Copy SourceFiles="@(OriginalScriptFiles)" DestinationFolder="$(MSBuildThisFileDirectory)\tools\signed" SkipUnchangedFiles="true" />
<ItemGroup>
<ScriptFilesToSign Include="$(MSBuildThisFileDirectory)\tools\signed\*.ps1">
<Authenticode>Microsoft400</Authenticode>
</ScriptFilesToSign>
</ItemGroup>
<SignFiles Files="@(ScriptFilesToSign)" Type="$(SignType)" BinariesDirectory="$(MSBuildThisFileDirectory)\tools\signed"
IntermediatesDirectory="$(MSBuildThisFileDirectory)\tools" ESRPSigning="$(ESRPSigning)" UseBearerToken="$(UseBearerToken)" />
</Target>
<Target Name="AfterBuild">
<PropertyGroup>
<OutDir>$(PackageOutputDir)</OutDir>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Extensions.targets"/>

<PropertyGroup>
<RoslynCopyToOutDir Condition="$(RoslynCopyToOutDir) == ''">true</RoslynCopyToOutDir>
<RoslynRegisterInConfig Condition="$(RoslynRegisterInConfig) == ''">true</RoslynRegisterInConfig>
<RoslynToolPath Condition="'$(RoslynToolPath)' == ''">$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\$roslynToolPath$'))</RoslynToolPath>
</PropertyGroup>

<Target Name="SetRoslynCompilerFiles" DependsOnTargets="LocateRoslynCompilerFiles">
<Target Name="SetRoslynCompilerFiles" >
<Message Text="Using Roslyn from '$(RoslynToolPath)' folder" />
<ItemGroup>
<RoslynCompilerFiles Include="$(RoslynToolPath)\*">
Expand Down Expand Up @@ -37,14 +38,29 @@
</PropertyGroup>
</Target>

<Target Name="CopyRoslynCompilerFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory" DependsOnTargets="LocateRoslynToolsDestinationFolder;SetRoslynCompilerFiles" Condition="$(RoslynCopyToOutDir) == 'true'">
<Target Name="CopyRoslynCompilerFilesToOutputDirectory" AfterTargets="CopyFilesToOutputDirectory" DependsOnTargets="LocateRoslynToolsDestinationFolder;SetRoslynCompilerFiles" Condition="$(RoslynCopyToOutDir) == 'true'">
<Copy SourceFiles="@(RoslynCompilerFiles)" DestinationFolder="$(RoslynToolsDestinationFolder)" ContinueOnError="true" SkipUnchangedFiles="true" Retries="0" />
<ItemGroup Condition="'$(MSBuildLastTaskResult)' == 'True'" >
<FileWrites Include="$(RoslynToolsDestinationFolder)\*" />
</ItemGroup>
</Target>

<Target Name="CheckIfShouldKillVBCSCompiler" DependsOnTargets="LocateRoslynCompilerFiles;LocateRoslynToolsDestinationFolder">
<Target Name="UpdateRoslynCompilersInConfigFile" BeforeTargets="ResolveAssemblyReferences" Condition="$(RoslynRegisterInConfig) == 'true'">
<UpdateCompilerConfigRecord ConfigFile="web.config" Extension=".cs" Language="c#;cs;csharp" WarningLevel="4" Options="/langversion:default /nowarn:1659;1699;1701;612;618"
CompilerType="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, $compilerPlatformFQAN$"
Condition="Exists('web.config')" />
<UpdateCompilerConfigRecord ConfigFile="web.config" Extension=".vb" Language="vb;vbs;visualbasic;vbscript" WarningLevel="4" Options="/langversion:default /nowarn:41008,40000,40008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"
CompilerType="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, $compilerPlatformFQAN$"
Condition="Exists('web.config')" />
<UpdateCompilerConfigRecord ConfigFile="App.config" Extension=".cs" Language="c#;cs;csharp" WarningLevel="4" Options="/langversion:default /nowarn:1659;1699;1701"
CompilerType="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, $compilerPlatformFQAN$"
Condition="Exists('App.config')" />
<UpdateCompilerConfigRecord ConfigFile="App.config" Extension=".vb" Language="vb;vbs;visualbasic;vbscript" WarningLevel="4" Options="/langversion:default /nowarn:41008 /optionInfer+"
CompilerType="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, $compilerPlatformFQAN$"
Condition="Exists('App.config')" />
</Target>

<Target Name="CheckIfShouldKillVBCSCompiler" DependsOnTargets="LocateRoslynToolsDestinationFolder">
<CheckIfVBCSCompilerWillOverride src="$(RoslynToolPath)\VBCSCompiler.exe" dest="$(RoslynToolsDestinationFolder)\VBCSCompiler.exe">
<Output TaskParameter="WillOverride" PropertyName="ShouldKillVBCSCompiler" />
</CheckIfVBCSCompilerWillOverride>
Expand All @@ -60,5 +76,6 @@

<UsingTask TaskName="KillProcess" AssemblyFile="..\..\tasks\DotNetCompilerPlatformTasks.dll" />
<UsingTask TaskName="CheckIfVBCSCompilerWillOverride" AssemblyFile="..\..\tasks\DotNetCompilerPlatformTasks.dll" />
<UsingTask TaskName="UpdateCompilerConfigRecord" AssemblyFile="..\..\tasks\DotNetCompilerPlatformTasks.dll" />

</Project>

This file was deleted.

This file was deleted.

Loading

0 comments on commit 919235a

Please sign in to comment.