Remove batching requirements placed on code and document generator providers

- #8419
- perform batching and `@(ServiceFileReference)` and `@(Compile)` additions in common code
  - take advantage of new simplicity in `DefaultDocumentGenerator` target
- add metadata serialization / deserialization in support of passing items into `<MSBuild />`
  - also ensure metadata values are escaped before calling `ITaskItem.SetMetadata(...)`
- correct typos in Microsoft.Extensions.ApiDescription.Client.* e.g. in comments and metadata names
- move last remaining `GenerationTasks` file

nits:
- combine `_ServiceProjectReferenceGenerator_Restore` and `_ServiceProjectReferenceGenerator_Build` targets
  - only build web sites projects once
- remove unused `buildMultiTargeting` targets
- remove qualification of metadata listed in an `<ItemDefinitionGroup />`; will always exist
- add / remove a few `Condition`s that were missing / redundant
- move properties users won't normally set to Microsoft.Extensions.ApiDescription.Client.targets
- shorten lines in MSBuild files
This commit is contained in:
Doug Bunting 2018-09-06 15:48:55 -07:00
parent 3f001750ad
commit 87e304334d
No known key found for this signature in database
GPG Key ID: 888B4EB7822B32E9
9 changed files with 377 additions and 174 deletions

View File

@ -0,0 +1,34 @@
// 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 Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.Extensions.ApiDescription.Client
{
/// <summary>
/// Restore <see cref="ITaskItem"/>s from given property value.
/// </summary>
public class GetCurrentItems : Task
{
/// <summary>
/// The property value to deserialize.
/// </summary>
[Required]
public string Input { get; set; }
/// <summary>
/// The restored <see cref="ITaskItem"/>s. Will never contain more than one item.
/// </summary>
[Output]
public ITaskItem[] Outputs { get; set; }
/// <inheritdoc />
public override bool Execute()
{
Outputs = new[] { MetadataSerializer.DeserializeMetadata(Input) };
return true;
}
}
}

View File

@ -61,18 +61,21 @@ namespace Microsoft.Extensions.ApiDescription.Client
if (string.IsNullOrEmpty(@namespace))
{
@namespace = isTypeScript ? CSharpNamespace : TypeScriptNamespace;
newItem.SetMetadata("Namespace", @namespace);
MetadataSerializer.SetMetadata(newItem, "Namespace", @namespace);
}
var outputPath = item.GetMetadata("OutputPath");
if (string.IsNullOrEmpty(outputPath))
{
var className = item.GetMetadata("ClassName");
outputPath = className + (isTypeScript ? ".ts" : ".cs");
outputPath = $"{className}{(isTypeScript ? ".ts" : ".cs")}";
}
outputPath = GetFullPath(outputPath);
newItem.SetMetadata("OutputPath", outputPath);
MetadataSerializer.SetMetadata(newItem, "OutputPath", outputPath);
// Add metadata which may be used as a property and passed to an inner build.
newItem.SetMetadata("SerializedMetadata", MetadataSerializer.SerializeMetadata(newItem));
}
Outputs = outputs.ToArray();

View File

@ -52,6 +52,8 @@ namespace Microsoft.Extensions.ApiDescription.Client
outputPath = className + (isTypeScript ? ".ts" : ".cs");
}
// Add metadata which may be used as a property and passed to an inner build.
newItem.SetMetadata("SerializedMetadata", MetadataSerializer.SerializeMetadata(newItem));
outputPath = GetFullPath(outputPath);
newItem.SetMetadata("OutputPath", outputPath);
}

View File

@ -95,7 +95,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
}
documentPath = GetFullPath(documentPath);
newItem.SetMetadata("DocumentPath", documentPath);
MetadataSerializer.SetMetadata(newItem, "DocumentPath", documentPath);
}
Outputs = outputs.ToArray();

View File

@ -0,0 +1,147 @@
// 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.Collections.Generic;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.Extensions.ApiDescription.Client
{
/// <summary>
/// Utility methods to serialize and deserialize <see cref="ITaskItem"/> metadata.
/// </summary>
/// <remarks>
/// Based on and uses the same escaping as
/// https://github.com/Microsoft/msbuild/blob/e70a3159d64f9ed6ec3b60253ef863fa883a99b1/src/Shared/EscapingUtilities.cs
/// </remarks>
public static class MetadataSerializer
{
private static readonly char[] CharsToEscape = { '%', '*', '?', '@', '$', '(', ')', ';', '\'' };
private static readonly HashSet<char> CharsToEscapeHash = new HashSet<char>(CharsToEscape);
/// <summary>
/// Add the given <paramref name="key"/> and <paramref name="value"/> to the <paramref name="item"/>. Or,
/// modify existing value to be <paramref name="value"/>.
/// </summary>
/// <param name="item">The <see cref="ITaskItem"/> to update.</param>
/// <param name="key">The name of the new metadata.</param>
/// <param name="value">The value of the new metadata. Assumed to be unescaped.</param>
/// <remarks>Uses same hex-encoded format as MSBuild's EscapeUtilities.</remarks>
public static void SetMetadata(ITaskItem item, string key, string value)
{
if (item is ITaskItem2 item2)
{
item2.SetMetadataValueLiteral(key, value);
return;
}
if (value.IndexOfAny(CharsToEscape) == -1)
{
item.SetMetadata(key, value);
return;
}
var builder = new StringBuilder();
EscapeValue(value, builder);
item.SetMetadata(key, builder.ToString());
}
/// <summary>
/// Serialize metadata for use as a property value passed into an inner build.
/// </summary>
/// <param name="item">The item to serialize.</param>
/// <returns>A <see cref="string"/> containing the serialized metadata.</returns>
/// <remarks>Uses same hex-encoded format as MSBuild's EscapeUtilities.</remarks>
public static string SerializeMetadata(ITaskItem item)
{
var builder = new StringBuilder();
if (item is ITaskItem2 item2)
{
builder.Append($"Identity={item2.EvaluatedIncludeEscaped}");
var metadata = item2.CloneCustomMetadataEscaped();
foreach (var key in metadata.Keys)
{
var value = metadata[key];
builder.Append($"|{key.ToString()}={value.ToString()}");
}
}
else
{
builder.Append($"Identity=");
EscapeValue(item.ItemSpec, builder);
var metadata = item.CloneCustomMetadata();
foreach (var key in metadata.Keys)
{
builder.Append($"|{key.ToString()}=");
var value = metadata[key];
EscapeValue(value.ToString(), builder);
}
}
return builder.ToString();
}
/// <summary>
/// Recreate an <see cref="ITaskItem"/> with metadata encoded in given <paramref name="value"/>.
/// </summary>
/// <param name="value">The serialized metadata.</param>
/// <returns>The deserialized <see cref="ITaskItem"/>.</returns>
public static ITaskItem DeserializeMetadata(string value)
{
var metadata = value.Split('|');
var item = new TaskItem();
// TaskItem implements ITaskITem2 explicitly and ITaskItem implicitly.
var item2 = (ITaskItem2)item;
foreach (var segment in metadata)
{
var keyAndValue = segment.Split(new[] { '=' }, count: 2);
if (string.Equals("Identity", keyAndValue[0]))
{
item2.EvaluatedIncludeEscaped = keyAndValue[1];
continue;
}
item2.SetMetadata(keyAndValue[0], keyAndValue[1]);
}
return item;
}
private static void EscapeValue(string value, StringBuilder builder)
{
if (string.IsNullOrEmpty(value))
{
builder.Append(value);
return;
}
if (value.IndexOfAny(CharsToEscape) == -1)
{
builder.Append(value);
return;
}
foreach (var @char in value)
{
if (CharsToEscapeHash.Contains(@char))
{
builder.Append('%');
builder.Append(HexDigitChar(@char / 0x10));
builder.Append(HexDigitChar(@char & 0x0F));
continue;
}
builder.Append(@char);
}
}
private static char HexDigitChar(int x)
{
return (char)(x + (x < 10 ? '0' : ('a' - 10)));
}
}
}

View File

@ -6,49 +6,32 @@
<_ApiDescriptionTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_ApiDescriptionTasksAssemblyTarget)/Microsoft.Extensions.ApiDescription.Client.dll</_ApiDescriptionTasksAssemblyPath>
<_ApiDescriptionTasksAssemblyTarget />
</PropertyGroup>
<UsingTask TaskName="GetCurrentItems" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
<UsingTask TaskName="GetFileReferenceMetadata" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
<UsingTask TaskName="GetProjectReferenceMetadata" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
<UsingTask TaskName="GetUriReferenceMetadata" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
<UsingTask TaskName="Microsoft.Extensions.ApiDescription.Client.DownloadFile" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
<!-- Settings users may update as they see fit. -->
<PropertyGroup>
<ServiceProjectReferenceCheckIfNewer Condition="'$(ServiceProjectReferenceCheckIfNewer)' == ''">true</ServiceProjectReferenceCheckIfNewer>
<ServiceProjectReferenceCheckIfNewer
Condition="'$(ServiceProjectReferenceCheckIfNewer)' == ''">true</ServiceProjectReferenceCheckIfNewer>
<ServiceProjectReferenceDirectory
Condition="'$(ServiceProjectReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceProjectReferenceDirectory)'))</ServiceProjectReferenceDirectory>
Condition="'$(ServiceProjectReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceProjectReferenceDirectory)'))</ServiceProjectReferenceDirectory>
<ServiceUriReferenceCheckIfNewer Condition="'$(ServiceUriReferenceCheckIfNewer)' == ''">true</ServiceUriReferenceCheckIfNewer>
<ServiceUriReferenceCheckIfNewer
Condition="'$(ServiceUriReferenceCheckIfNewer)' == ''">true</ServiceUriReferenceCheckIfNewer>
<ServiceUriReferenceDirectory
Condition="'$(ServiceUriReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceUriReferenceDirectory)'))</ServiceUriReferenceDirectory>
Condition="'$(ServiceUriReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceUriReferenceDirectory)'))</ServiceUriReferenceDirectory>
<ServiceFileReferenceCheckIfNewer Condition="'$(ServiceFileReferenceCheckIfNewer)' == ''">true</ServiceFileReferenceCheckIfNewer>
<ServiceFileReferenceCheckIfNewer
Condition="'$(ServiceFileReferenceCheckIfNewer)' == ''">true</ServiceFileReferenceCheckIfNewer>
<ServiceFileReferenceDirectory
Condition="'$(ServiceFileReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceFileReferenceDirectory)'))</ServiceFileReferenceDirectory>
<ServiceFileReferenceCSharpNamespace Condition="'$(ServiceFileReferenceCSharpNamespace)' == ''">$(RootNamespace)</ServiceFileReferenceCSharpNamespace>
<ServiceFileReferenceTypeScriptNamespace Condition="'$(ServiceFileReferenceTypeScriptNamespace)' == ''">$(RootNamespace)</ServiceFileReferenceTypeScriptNamespace>
<DefaultDocumentGeneratorDependsOn>
_DefaultDocumentGenerator_GetMetadata;
_DefaultDocumentGenerator_Core;
_DefaultDocumentGenerator_SetMetadata
</DefaultDocumentGeneratorDependsOn>
<ServiceProjectReferenceGeneratorDependsOn>
_ServiceProjectReferenceGenerator_GetTargetFramework;
_ServiceProjectReferenceGenerator_GetProjectTargetPath;
_ServiceProjectReferenceGenerator_Restore;
_ServiceProjectReferenceGenerator_Build;
_ServiceProjectReferenceGenerator_Core
</ServiceProjectReferenceGeneratorDependsOn>
<ServiceUriReferenceGeneratorDependsOn>
_ServiceUriReferenceGenerator_GetMetadata;
_ServiceUriReferenceGenerator_Core
</ServiceUriReferenceGeneratorDependsOn>
<ServiceFileReferenceGeneratorDependsOn>
_CheckServiceReferences;
ServiceProjectReferenceGenerator;
ServiceUriReferenceGenerator;
_ServiceFileReferenceGenerator_GetMetadata;
_ServiceFileReferenceGenerator_Core
</ServiceFileReferenceGeneratorDependsOn>
Condition="'$(ServiceFileReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceFileReferenceDirectory)'))</ServiceFileReferenceDirectory>
<ServiceFileReferenceCSharpNamespace
Condition="'$(ServiceFileReferenceCSharpNamespace)' == ''">$(RootNamespace)</ServiceFileReferenceCSharpNamespace>
<ServiceFileReferenceTypeScriptNamespace
Condition="'$(ServiceFileReferenceTypeScriptNamespace)' == ''">$(RootNamespace)</ServiceFileReferenceTypeScriptNamespace>
</PropertyGroup>
<!--
@ -59,6 +42,33 @@
<ServiceProjectReference>
<!-- Name of the API description document generator. -->
<DocumentGenerator>Default</DocumentGenerator>
<!-- Server project metadata which is likely applicable to all document generators. -->
<!--
Full path of the project's generated assembly. Corresponds to $(TargetPath). Because common code builds server
projects, file exists prior to document generator invocation.
-->
<ProjectAssemblyPath />
<!-- Server project's chosen configuration. Likely matches client project's configuration. -->
<ProjectConfiguration />
<!--
Server project's extensions path. Corresponds to $(MSBuildProjectExtensionsPath). User must set this if
server project's value is not 'obj/'.
-->
<ProjectExtensionsPath />
<!-- Runtime identifier to use when building the server project. -->
<ProjectRuntimeIdentifier />
<!-- Server project's target framework. Defaults to $(TargetFramewok) or first of $(TargetFrameworks). -->
<ProjectTargetFramework />
<!-- Metadata specific to the Default document generator (though other document generators are free to use it). -->
<!--
Options added to Default document generator tool's command line. Defaults to
$(DefaultDocumentGeneratorDefaultOptions) if that is set in the client project.
-->
<DefaultDocumentGeneratorOptions />
<!--
Name of the document to generate. Passed to the %(Method) when using Default document generator. Default is set
in server project, falling back to "v1".
@ -84,36 +94,19 @@
the %(Service) fails. Default is set in server project and metadata has no further fallback.
-->
<Uri />
<!--
Full path of the project's generated assembly. Corresponds to $(TargetPath). Because common code builds server
projects, file exists prior to document generator invocation.
-->
<ProjectAssemblyPath />
<!-- Server project's chosen configuration. Likely matches client project's configuration. -->
<ProjectConfiguration />
<!--
Server project's extensions path. Corresponds to $(MSBuildProjectExtensionsPath). Must set this if project's
value is not 'obj/'.
-->
<ProjectExtensionsPath />
<!-- Runtime identifier to use when building the server project. -->
<ProjectRuntimeIdentifier />
<!-- Server project's target framework. Defaults to $(TargetFramewok) or first of $(TargetFrameworks). -->
<ProjectTargetFramework />
</ServiceProjectReference>
<ServiceUriReference>
<!--
Full path where the API description document is placed. Default filename is based on %(Identity).
Filenames and relative paths (if explicitly set) are combined with $(ServiceProjectReferenceDirectory).
Filenames and relative paths (if explicitly set) are combined with $(ServiceUriReferenceDirectory).
-->
<DocumentPath />
</ServiceUriReference>
<ServiceFileReference>
<!-- Name of the class to generate. -->
<ClassName>%(Filename)Client</ClassName>
<!-- Name of the class to generate. Defaults to %(Filename)Client but with an uppercase first letter. -->
<ClassName />
<!-- Code generator to use. Required. -->
<CodeGenerator />
<!--
@ -124,7 +117,7 @@
<!--
Path to place generated code. Code generator may interpret path as a filename or directory. Default filename or
folder name is %(ClassName).[cs|ts]. Filenames and relative paths (if explicitly set) are combined with
$(ServiceProjectReferenceDirectory).
$(ServiceFileReferenceDirectory).
-->
<OutputPath />
</ServiceFileReference>

View File

@ -1,11 +1,34 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project>
<!-- Internal settings for Microsoft.Extensions.ApiDescription.Client.targets use. Not intended for customization. -->
<PropertyGroup>
<ServiceProjectReferenceGeneratorDependsOn>
_ServiceProjectReferenceGenerator_GetTargetFramework;
_ServiceProjectReferenceGenerator_GetProjectTargetPath;
_ServiceProjectReferenceGenerator_Build;
_ServiceProjectReferenceGenerator_Core;
_ServiceProjectReferenceGenerator_SetMetadata
</ServiceProjectReferenceGeneratorDependsOn>
<ServiceUriReferenceGeneratorDependsOn>
_ServiceUriReferenceGenerator_GetMetadata;
_ServiceUriReferenceGenerator_Core
</ServiceUriReferenceGeneratorDependsOn>
<ServiceFileReferenceGeneratorDependsOn>
_CheckServiceReferences;
ServiceProjectReferenceGenerator;
ServiceUriReferenceGenerator;
_ServiceFileReferenceGenerator_GetMetadata;
_ServiceFileReferenceGenerator_Core;
_ServiceFileReferenceGenerator_SetMetadata
</ServiceFileReferenceGeneratorDependsOn>
</PropertyGroup>
<Target Name="_CheckServiceReferences">
<Error Condition="'@(ServiceProjectReference)' != '' AND '%(ServiceProjectReference.CodeGenerator)' == ''"
<Error Condition="'@(ServiceProjectReference)' != '' AND '%(CodeGenerator)' == ''"
Text="ServiceProjectReference items '@(ServiceProjectReference)' lack CodeGenerator metadata." />
<Error Condition="'@(ServiceUriReference)' != '' AND '%(ServiceUriReference.CodeGenerator)' == ''"
<Error Condition="'@(ServiceUriReference)' != '' AND '%(CodeGenerator)' == ''"
Text="ServiceUriReference items '@(ServiceUriReference)' lack CodeGenerator metadata." />
<Error Condition="'@(ServiceFileReference)' != '' AND '%(ServiceFileReference.CodeGenerator)' == ''"
<Error Condition="'@(ServiceFileReference)' != '' AND '%(CodeGenerator)' == ''"
Text="ServiceFileReference items '@(ServiceFileReference)' lack CodeGenerator metadata." />
</Target>
@ -38,7 +61,7 @@
</PropertyGroup>
<ItemGroup>
<ServiceProjectReference Update="@(ServiceProjectReference)" Condition="'%(FullPath)' == '$(_FullPath)'">
<TargetFramework Condition="'%(ServiceProjectReference.TargetFramework)' == ''">$(_TargetFramework)</TargetFramework>
<ProjectTargetFramework Condition="'%(ProjectTargetFramework)' == ''">$(_TargetFramework)</ProjectTargetFramework>
</ServiceProjectReference>
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>
@ -53,17 +76,19 @@
<!-- Metadata setup phase 2: Ensure items have ProjectTargetPath metadata. Call GetTargetPath in the target project. -->
<!-- Inputs and outputs cause MSBuild to run target unconditionally and batch it (run once per TargetFramework x project combination). -->
<Target Name="_ServiceProjectReferenceGenerator_GetProjectTargetPath"
Inputs="%(ServiceProjectReference.TargetFramework)%(FullPath)"
Outputs="&lt;not-a-file !&gt;">
Inputs="%(ServiceProjectReference.TargetFramework)%(FullPath)')"
Outputs="&lt;not-a-file !&gt;">
<PropertyGroup>
<_FullPath>%(ServiceProjectReference.FullPath)</_FullPath>
<_TargetFramework>%(ServiceProjectReference.TargetFramework)</_TargetFramework>
<_TargetFramework>%(ServiceProjectReference.ProjectTargetFramework)</_TargetFramework>
</PropertyGroup>
<ItemGroup>
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>
<Message Importance="high" Text="%0A_ServiceProjectReferenceGenerator_GetProjectTargetPath: '$(_FullPath)' '$(_TargetFramework)'" />
<Message
Importance="high"
Text="%0A_ServiceProjectReferenceGenerator_GetProjectTargetPath: '$(_FullPath)' '$(_TargetFramework)'" />
<MSBuild Projects="$(_FullPath)"
Properties="TargetFramework=$(_TargetFramework)"
RebaseOutputs="true"
@ -78,7 +103,7 @@
</PropertyGroup>
<ItemGroup>
<ServiceProjectReference Update="@(ServiceProjectReference)"
Condition="'%(FullPath)' == '$(_FullPath)' AND '%(ServiceProjectReference.TargetFramework)' == '$(_TargetFramework)'">
Condition="'%(ServiceProjectReference.FullPath)' == '$(_FullPath)' AND '%(ProjectTargetFramework)' == '$(_TargetFramework)'">
<ProjectTargetPath>$(_ProjectTargetPath)</ProjectTargetPath>
</ServiceProjectReference>
<_Temporary Remove="@(_Temporary)" />
@ -91,99 +116,85 @@
</PropertyGroup>
</Target>
<Target Name="_ServiceProjectReferenceGenerator_Restore"
Condition="'$(BuildProjectReferences)' == 'true'"
Inputs="@(ServiceProjectReference)"
Outputs="@(ServiceProjectReference -> '%(Directory)obj\project.assets.json')">
<MSBuild Projects="@(ServiceProjectReference -> '%(FullPath)')"
BuildInParallel="$(BuildInParallel)"
RemoveProperties="TargetFramework;TargetFrameworks;RuntimeIdentifier"
Targets="Restore" />
</Target>
<Target Name="_ServiceProjectReferenceGenerator_Build"
Condition="'$(BuildProjectReferences)' == 'true'"
Inputs="@(ServiceProjectReference)"
Outputs="@(ServiceProjectReference -> '%(ProjectTargetPath)')">
<MSBuild Projects="@(ServiceProjectReference)"
Outputs="%(ProjectTargetPath)">
<MSBuild Projects="@(ServiceProjectReference -> Distinct())"
BuildInParallel="$(BuildInParallel)"
RemoveProperties="TargetFrameworks;RuntimeIdentifier"
Targets="Build" />
RemoveProperties="TargetFramework;TargetFrameworks;RuntimeIdentifier"
Targets="Restore;Build" />
</Target>
<Target Name="_ServiceProjectReferenceGenerator_Core"
Condition="'@(ServiceProjectReference)' != ''"
DependsOnTargets="@(ServiceProjectReference -> '%(DocumentGenerator)DocumentGenerator')" />
<Target Name="_ServiceProjectReferenceGenerator_GetItems">
<GetCurrentItems Input="$(GeneratorMetadata)">
<Output TaskParameter="Outputs" ItemName="CurrentServiceProjectReference" />
</GetCurrentItems>
</Target>
<Target Name="ServiceProjectReferenceGenerator"
Condition="'@(ServiceProjectReference)' != ''"
DependsOnTargets="$(ServiceProjectReferenceGeneratorDependsOn)" />
<Target Name="_ServiceProjectReferenceGenerator_Inner" DependsOnTargets="_ServiceProjectReferenceGenerator_GetItems;$(GeneratorTarget)" />
<Target Name="_ServiceProjectReferenceGenerator_Core" Inputs="@(ServiceProjectReference)" Outputs="%(DocumentPath)">
<Message Importance="high" Text="%0A_ServiceProjectReferenceGenerator_Core:" />
<Message Importance="high" Text=" @(ServiceProjectReference): %(DocumentPath)" />
<MSBuild BuildInParallel="$(BuildInParallel)"
Projects="$(MSBuildProjectFullPath)"
Properties="GeneratorTargetPath=%(ServiceProjectReference.DocumentPath);GeneratorTarget=%(DocumentGenerator)DocumentGenerator;GeneratorMetadata=%(SerializedMetadata);TargetFramework=%(ProjectTargetFramework)"
RemoveProperties="TargetFrameworks;RuntimeIdentifier"
Targets="_ServiceProjectReferenceGenerator_Inner" />
</Target>
<Target Name="_ServiceProjectReferenceGenerator_SetMetadata" Condition="'@(ServiceProjectReference)' != ''">
<!-- _ServiceProjectReferenceGenerator_GetMetadata guarantees %(DocumentPath) values are unique. -->
<ItemGroup>
<ServiceFileReference Remove="@(ServiceProjectReference -> '%(DocumentPath)')" />
<!-- Condition here is temporary. Useful while DefaultDocumentGenerator fails. -->
<ServiceFileReference Include="@(ServiceProjectReference -> '%(DocumentPath)')"
Condition="Exists('%(DocumentPath)')"
SourceProject="%(FullPath)" />
</ItemGroup>
</Target>
<Target Name="ServiceProjectReferenceGenerator" DependsOnTargets="$(ServiceProjectReferenceGeneratorDependsOn)" />
<!-- DefaultDocumentGenerator -->
<Target Name="_DefaultDocumentGenerator_GetMetadata">
<Target Name="DefaultDocumentGenerator">
<Message Importance="high" Text="%0ADefaultDocumentGenerator:" />
<Message Importance="high" Text=" @(CurrentServiceProjectReference): %(DocumentPath)" />
<ItemGroup>
<_Temporary Remove="@(_Temporary)" />
<_Temporary Include="@(ServiceProjectReference -> WithMetadataValue('DocumentGenerator', 'Default'))" />
<!-- @(CurrentServiceProjectReference) item group will never contain more than one item. -->
<CurrentServiceProjectReference Update="@(CurrentServiceProjectReference)">
<Command>dotnet getdocument --no-build --project %(FullPath) --output %(DocumentPath)</Command>
<DefaultDocumentGeneratorOptions
Condition="'%(DefaultDocumentGeneratorOptions)' == ''">$(DefaultDocumentGeneratorDefaultOptions)</DefaultDocumentGeneratorOptions>
</CurrentServiceProjectReference>
<CurrentServiceProjectReference Update="@(_Temporary)">
<Command>%(Command) --framework %(ProjectTargetFramework)</Command>
<Command Condition="'%(ProjectConfiguration)' == ''">%(Command) --configuration $(Configuration)</Command>
<Command Condition="'%(ProjectConfiguration)' != ''">%(Command) --configuration %(ProjectConfiguration)</Command>
<Command Condition="'%(Method)' != ''">%(Command) --method %(Method)</Command>
<Command Condition="'%(Service)' != ''">%(Command) --service %(Service)</Command>
<Command Condition="'%(Uri)' != ''">%(Command) --uri %(Uri)</Command>
<Command
Condition="'%(DefaultDocumentGeneratorOptions)' != ''">%(Command) %(DefaultDocumentGeneratorOptions)</Command>
</CurrentServiceProjectReference>
</ItemGroup>
<Error Condition="'@(_Temporary)' != '' AND '%(_Temporary.Method)' != '' AND '%(_Temporary.Uri)' != ''"
Text="ServiceProjectReference items '@(_Temporary)' have both Method and Uri metadata." />
<Error Condition="'@(_Temporary)' != '' AND '%(_Temporary.Service)' != '' AND '%(_Temporary.Uri)' != ''"
Text="ServiceProjectReference items '@(_Temporary)' have both Service and Uri metadata." />
<Message Importance="high" Text="%0A%(CurrentServiceProjectReference.Command)" />
<Exec IgnoreExitCode="$([System.IO.File]::Exists('%(DocumentPath)'))" Command="%(CurrentServiceProjectReference.Command)" />
</Target>
<Target Name="_DefaultDocumentGenerator_Core" Inputs="%(_Temporary.ProjectTargetPath)" Outputs="%(_Temporary.DocumentPath)">
<!-- aspnetcore2swagger -->
<PropertyGroup>
<_Command>dotnet getdocument --configuration $(Configuration) --no-build</_Command>
</PropertyGroup>
<ItemGroup>
<_Temporary Update="@(_Temporary)">
<Options
Condition="'%(_Temporary.Options)' == '' AND '$(DefaultDocumentGeneratorDefaultOptions)' != ''">$(DefaultDocumentGeneratorDefaultOptions)</Options>
<Command>$(_Command) --project %(FullPath) --output %(DocumentPath) --framework %(TargetFramework)</Command>
</_Temporary>
<_Temporary Update="@(_Temporary)">
<Command Condition="'%(_Temporary.Uri)' != ''">%(Command) --uri %(_Temporary.Uri)</Command>
</_Temporary>
<_Temporary Update="@(_Temporary)">
<Command Condition="'%(_Temporary.Service)' != ''">%(Command) --service %(_Temporary.Service) --method %(_Temporary.Method)</Command>
</_Temporary>
<_Temporary Update="@(_Temporary)">
<Command Condition="'%(_Temporary.Options)' != ''">%(Command) %(_Temporary.Options)</Command>
</_Temporary>
</ItemGroup>
<Message Importance="high" Text="%0A%(_Temporary.Command)" />
<Exec IgnoreExitCode="$([System.IO.File]::Exists('%(DocumentPath)'))" Command="%(_Temporary.Command)" />
</Target>
<!--
Separate from _DefaultDocumentGenerator_Core to ensure ServiceFileReference items are complete even if
ServiceProjectReference items are not built in any batch.
-->
<Target Name="_DefaultDocumentGenerator_SetMetadata" Condition="'@(_Temporary)' != ''">
<ItemGroup>
<ServiceFileReference Remove="@(_Temporary -> '%(DocumentPath)')" />
<!-- Condition here is temporary. Useful while DefaultDocumentGenerator fails. -->
<ServiceFileReference Include="@(_Temporary -> '%(DocumentPath)')"
Condition="Exists('%(_Temporary.DocumentPath)')"
SourceProject="%(_Temporary.FullPath)" />
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>
</Target>
<Target Name="DefaultDocumentGenerator" DependsOnTargets="$(DefaultDocumentGeneratorDependsOn)" />
<!-- ServiceUriReference support -->
<Target Name="_ServiceUriReferenceGenerator_GetMetadata">
<Target Name="_ServiceUriReferenceGenerator_GetMetadata" Condition="'@(ServiceUriReference)' != ''">
<ItemGroup>
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>
<GetUriReferenceMetadata DocumentDirectory="$(ServiceUriReferenceDirectory)" Inputs="@(ServiceUriReference)">
<GetUriReferenceMetadata Inputs="@(ServiceUriReference)" DocumentDirectory="$(ServiceUriReferenceDirectory)">
<Output TaskParameter="Outputs" ItemName="_Temporary" />
</GetUriReferenceMetadata>
@ -199,9 +210,10 @@
DestinationPath="%(DocumentPath)"
Overwrite="$(ServiceUriReferenceCheckIfNewer)" />
<!-- _ServiceUriReferenceGenerator_GetMetadata guarantees %(DocumentPath) values are unique. -->
<ItemGroup>
<ServiceFileReference Remove="@(ServiceUriReference -> '%(DocumentPath)')" />
<ServiceFileReference Include="@(ServiceUriReference -> '%(DocumentPath)')" SourceUri="%(ServiceUriReference.Identity)" />
<ServiceFileReference Include="@(ServiceUriReference -> '%(DocumentPath)')" SourceUri="%(Identity)" />
</ItemGroup>
</Target>
@ -209,12 +221,15 @@
<!-- ServiceFileReference support -->
<Target Name="_ServiceFileReferenceGenerator_GetMetadata">
<Target Name="_ServiceFileReferenceGenerator_GetMetadata" Condition="'@(ServiceFileReference)' != ''">
<ItemGroup>
<_Temporary Remove="@(_Temporary)" />
</ItemGroup>
<GetFileReferenceMetadata DocumentDirectory="$(ServiceFileReferenceDirectory)" Inputs="@(ServiceFileReference)">
<GetFileReferenceMetadata Inputs="@(ServiceFileReference)"
CSharpNamespace="$(ServiceFileReferenceCSharpNamespace)"
OutputDirectory="$(ServiceFileReferenceDirectory)"
TypeScriptNamespace="$(ServiceFileReferenceTypeScriptNamespace)">
<Output TaskParameter="Outputs" ItemName="_Temporary" />
</GetFileReferenceMetadata>
@ -225,9 +240,38 @@
</ItemGroup>
</Target>
<Target Name="_ServiceFileReferenceGenerator_Core"
Condition="'@(ServiceFileReference)' != ''"
DependsOnTargets="@(ServiceFileReference -> '%(CodeGenerator)CodeGenerator')" />
<Target Name="_ServiceFileReferenceGenerator_GetItems">
<GetCurrentItems Input="$(GeneratorMetadata)">
<Output TaskParameter="Outputs" ItemName="CurrentServiceFileReference" />
</GetCurrentItems>
</Target>
<Target Name="ServiceFileReferenceGenerator" BeforeTargets="BeforeCompile" DependsOnTargets="$(ServiceFileReferenceGeneratorDependsOn)" />
<Target Name="_ServiceFileReferenceGenerator_Inner" DependsOnTargets="_ServiceFileReferenceGenerator_GetItems;$(GeneratorTarget)" />
<Target Name="_ServiceFileReferenceGenerator_Core" Inputs="@(ServiceFileReference)" Outputs="%(OutputPath)">
<Message Importance="high" Text="%0A_ServiceFileReferenceGenerator_Core:" />
<Message Importance="high" Text=" @(ServiceFileReference): %(DocumentPath)" />
<MSBuild BuildInParallel="$(BuildInParallel)"
Projects="$(MSBuildProjectFullPath)"
Properties="GeneratorTargetPath=%(ServiceProjectReference.OutputPath);GeneratorTarget=%(CodeGenerator)CodeGenerator;GeneratorMetadata=%(SerializedMetadata);TargetFramework=%(ProjectTargetFramework)"
RemoveProperties="TargetFrameworks;RuntimeIdentifier"
Targets="_ServiceFileReferenceGenerator_Inner" />
</Target>
<Target Name="_ServiceFileReferenceGenerator_SetMetadata" Condition="'@(ServiceFileReference)' != ''">
<!--
While %(DocumentPath) metadata may include duplicates (due to overlaps between ServiceUriReference and
ServiceProjectReference items), _ServiceFileReferenceGenerator_GetMetadata guarantees %(OutputPath) values are
unique.
-->
<ItemGroup>
<Compile Remove="@(ServiceFileReference -> '%(OutputPath)')" />
<Compile Include="@(ServiceFileReference -> '%(OutputPath)')" SourceDocument="%(FullPath)" />
</ItemGroup>
</Target>
<Target Name="ServiceFileReferenceGenerator"
BeforeTargets="BeforeCompile"
DependsOnTargets="$(ServiceFileReferenceGeneratorDependsOn)" />
</Project>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project>
<!-- ServiceProjectReference support -->
<Target Name="ServiceProjectReferenceGenerator">
<MsBuild Projects="$(MSBuildProjectFile)"
Targets="ServiceProjectReferenceGenerator"
Properties="TargetFramework=$(TargetFrameworks.Split(';')[0])"
RemoveProperties="TargetFrameworks;RuntimeIdentifier" />
</Target>
<!-- ServiceUriReference support -->
<Target Name="ServiceUriReferenceGenerator">
<MsBuild Projects="$(MSBuildProjectFile)"
Targets="ServiceUriReferenceGenerator"
Properties="TargetFramework=$(TargetFrameworks.Split(';')[0])"
RemoveProperties="TargetFrameworks;RuntimeIdentifier" />
</Target>
<!-- ServiceFileReference support -->
<Target Name="ServiceFileReferenceGenerator" BeforeTargets="BeforeCompile">
<MsBuild Projects="$(MSBuildProjectFile)"
Targets="ServiceFileReferenceGenerator"
Properties="TargetFramework=$(TargetFrameworks.Split(';')[0])"
RemoveProperties="TargetFrameworks;RuntimeIdentifier" />
</Target>
</Project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project>
<Target Name="ServiceFileReferenceGenerator" BeforeTargets="BeforeCompile">
<MsBuild Projects="$(MSBuildProjectFile)"
Targets="ServiceFileReferenceGenerator"
Properties="TargetFramework=$(TargetFrameworks.Split(';')[0])"
RemoveProperties="TargetFrameworks;RuntimeIdentifier" />
</Target>
</Project>