We are going to generate AssemblyInfo source from project properties.
@srivatsn @davkean Is it OK/worth pulling in a Roslyn dependency from Microsoft.DotNet.Core.Build.Tasks or should I just do it string-based?
Thinking about it, Roslyn feels like a big hammer for just attributes. If you need to generate code in a language agnostic way, you'll need the workspaces layer which is a lot of machinery. Strings may be fine here.
Why does generation require the workspaces layer?
The compiler layer has syntax factories which are language specific. To write code that's language agnostic you'd have to use the SyntaxGenerator type from the workspaces layer which basically forwards to a C#\VB implementation based on the project's language. The reason that's in workspaces is because it uses MEF to get at the language implementation without having to load both\all languages at the same time.
Ugh. MEF composition should be optional in these cases - you're no CodeDom replacement. :) But I digress.
What if we had a single target that gets override by each language to generate it? Similar to CoreCompile. We also need to think about how this is going to work with the desktop scenarios (such as ASP.NET Core on .NET Framework, or a library targeting .NET Framework), are we going to use DotNet.Core.Build.Tasks in those cases?
cc @eerhardt
Yeah, I think this can be simpler without Roslyn, for example, take a look at http://index/#Microsoft.Web.Publishing.Tasks/GenerateAssemblyInfo.cs,c303be12f39bda98.
Yeah, I think this can be simpler without Roslyn
Agreed. Let's just write out the text ourselves. :)
What if we had a single target that gets override by each language to generate it?
Yes. This is what @srivatsn and I discussed yesterday.
We also need to think about how this is going to work with the desktop scenarios (such as ASP.NET Core on .NET Framework, or a library targeting .NET Framework), are we going to use DotNet.Core.Build.Tasks in those cases?
Is there any reason we couldn't use DotNet.Core.Build.Tasks in those cases?
This could be a targets issue, but basically, in some cases for .NET Core we want to override specific targets (such as ResolveAssemblyReference), but not in the .NET Framework case.
This logic could all live in the same tasks dll, but long term we'll want to separate logic that's shared from logic that's not.
Do we even need a task or is a target like this sufficient?
FYI - here is the code in the CLI that does this today:
Or you could take the same approach I've taken in the past (I think I took this approach from Roslyn originally) and write it all in MSBuild:
<ItemGroup>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyCompanyAttribute">
<_Parameter1>Microsoft Corporation</_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyCopyrightAttribute">
<_Parameter1>漏 Microsoft Corporation. All rights reserved.</_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyProductAttribute">
<_Parameter1>Microsoft Connected Services</_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyConfigurationAttribute">
<_Parameter1>$(Configuration)</_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyCultureAttribute">
<_Parameter1></_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyTrademarkAttribute">
<_Parameter1></_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyVersionAttribute">
<_Parameter1>$(AssemblyVersion)</_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyFileVersionAttribute">
<_Parameter1>$(BuildVersion)</_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Reflection.AssemblyInformationalVersionAttribute">
<_Parameter1>$(BuildVersion)</_Parameter1>
</AssemblyVersionAttribute>
<AssemblyVersionAttribute Include="System.Resources.NeutralResourcesLanguageAttribute">
<_Parameter1>en-US</_Parameter1>
</AssemblyVersionAttribute>
</ItemGroup>
<Target Name="GenerateAssemblyInfoFile">
<WriteCodeFragment AssemblyAttributes="@(AssemblyVersionAttribute)"
Language="C#"
OutputFile="$(MSBuildProjectDirectory)\GlobalAssemblyInfo.cs">
<Output TaskParameter="OutputFile" ItemName="Compile" />
<Output TaskParameter="OutputFile" ItemName="FileWrites" />
</WriteCodeFragment>
</Target>
EDIT: sorry @srivatsn - I hadn't read your comment before replying. =x
We also need to think about how this is going to work with the desktop scenarios (such as ASP.NET Core on .NET Framework, or a library targeting .NET Framework), are we going to use DotNet.Core.Build.Tasks in those cases?
Is there any reason we couldn't use DotNet.Core.Build.Tasks in those cases?
We have other reasons why we are going to need these tasks and targets in those cases. For example implementing the PreserveCompliationContext property will need to generate the .deps.json file, and currently that lives in Microsoft.DotNet.Core.Build.Tasks.dll. Same goes for resolving assets out of the nuget lock file - that code lives in the same assembly.
Does WriteCodeFragment work xplat? It is implemented with CodeDom. Using it would certainly be simplest. Otherwise, once you start handling escaping the strings correctly and all, I think it will get gnarly without task support.
Ah, there's a fallback impementation for xplat https://github.com/Microsoft/msbuild/blob/xplat/src/XMakeTasks/WriteCodeFragment.cs
:) I'll go that way.
Most helpful comment
Do we even need a task or is a target like this sufficient?