Add first cut of Microsoft.Extensions.ApiDescription.Client package / project
- WIP in a number of ways
This commit is contained in:
parent
9daf5ff7a4
commit
95b4dc8ca0
|
|
@ -117,6 +117,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ap
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.Api.Analyzers.Test", "test\Mvc.Api.Analyzers.Test\Mvc.Api.Analyzers.Test.csproj", "{71C626FC-6408-494B-A127-38CB64F71324}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\dotnet-getdocument\dotnet-getdocument.csproj", "{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client", "src\Microsoft.Extensions.ApiDescription.Client\Microsoft.Extensions.ApiDescription.Client.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -575,6 +581,42 @@ Global
|
|||
{71C626FC-6408-494B-A127-38CB64F71324}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{71C626FC-6408-494B-A127-38CB64F71324}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{71C626FC-6408-494B-A127-38CB64F71324}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -619,6 +661,9 @@ Global
|
|||
{92D959F2-66B8-490A-BA33-DA4421EBC948} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{1B398182-9EAE-400B-A2BD-EFFAC0168A36} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{71C626FC-6408-494B-A127-38CB64F71324} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {D003597F-372F-4068-A2F0-353BE3C3B39A}
|
||||
|
|
|
|||
45
Mvc.sln
45
Mvc.sln
|
|
@ -178,6 +178,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ap
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorRendering", "benchmarkapps\RazorRendering\RazorRendering.csproj", "{D7C6A696-F232-4288-BCCD-367407E4A934}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\dotnet-getdocument\dotnet-getdocument.csproj", "{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client", "src\Microsoft.Extensions.ApiDescription.Client\Microsoft.Extensions.ApiDescription.Client.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -938,6 +944,42 @@ Global
|
|||
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -1010,6 +1052,9 @@ Global
|
|||
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{D7C6A696-F232-4288-BCCD-367407E4A934} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E}
|
||||
{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{2F683CF8-B055-46AE-BF83-9D1307F8D45F} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{34E3C302-B767-40C8-B538-3EE2BD4000C4} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A}
|
||||
|
|
|
|||
|
|
@ -54,9 +54,11 @@
|
|||
<MicrosoftAspNetCoreSessionPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreSessionPackageVersion>
|
||||
<MicrosoftAspNetCoreStaticFilesPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreStaticFilesPackageVersion>
|
||||
<MicrosoftAspNetCoreTestHostPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreTestHostPackageVersion>
|
||||
<MicrosoftAspNetCoreTestHost20PackageVersion>2.0.0</MicrosoftAspNetCoreTestHost20PackageVersion>
|
||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreTestingPackageVersion>
|
||||
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
|
||||
<MicrosoftAspNetWebApiClientPackageVersion>5.2.6</MicrosoftAspNetWebApiClientPackageVersion>
|
||||
<MicrosoftBuildUtilitiesCorePackageVersion>15.6.82</MicrosoftBuildUtilitiesCorePackageVersion>
|
||||
<MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion>
|
||||
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
|
||||
<MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-preview3-35359</MicrosoftCodeAnalysisRazorPackageVersion>
|
||||
|
|
@ -100,8 +102,10 @@
|
|||
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
||||
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
|
||||
<NewtonsoftJsonBsonPackageVersion>1.0.1</NewtonsoftJsonBsonPackageVersion>
|
||||
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
|
||||
<SystemComponentModelAnnotationsPackageVersion>4.5.0</SystemComponentModelAnnotationsPackageVersion>
|
||||
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.0</SystemDiagnosticsDiagnosticSourcePackageVersion>
|
||||
<SystemNetHttpPackageVersion>4.3.2</SystemNetHttpPackageVersion>
|
||||
<SystemThreadingTasksExtensionsPackageVersion>4.5.1</SystemThreadingTasksExtensionsPackageVersion>
|
||||
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
|
||||
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// 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 GetDocument
|
||||
{
|
||||
internal class AnsiConsole
|
||||
{
|
||||
public static readonly AnsiTextWriter _out = new AnsiTextWriter(Console.Out);
|
||||
|
||||
public static void WriteLine(string text)
|
||||
=> _out.WriteLine(text);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// 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.
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal static class AnsiConstants
|
||||
{
|
||||
public const string Reset = "\x1b[22m\x1b[39m";
|
||||
public const string Bold = "\x1b[1m";
|
||||
public const string Dark = "\x1b[22m";
|
||||
public const string Black = "\x1b[30m";
|
||||
public const string Red = "\x1b[31m";
|
||||
public const string Green = "\x1b[32m";
|
||||
public const string Yellow = "\x1b[33m";
|
||||
public const string Blue = "\x1b[34m";
|
||||
public const string Magenta = "\x1b[35m";
|
||||
public const string Cyan = "\x1b[36m";
|
||||
public const string Gray = "\x1b[37m";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
// 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.Text.RegularExpressions;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal class AnsiTextWriter
|
||||
{
|
||||
private readonly TextWriter _writer;
|
||||
|
||||
public AnsiTextWriter(TextWriter writer) => _writer = writer;
|
||||
|
||||
public void WriteLine(string text)
|
||||
{
|
||||
Interpret(text);
|
||||
_writer.Write(Environment.NewLine);
|
||||
}
|
||||
|
||||
private void Interpret(string value)
|
||||
{
|
||||
var matches = Regex.Matches(value, "\x1b\\[([0-9]+)?m");
|
||||
|
||||
var start = 0;
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
var length = match.Index - start;
|
||||
if (length != 0)
|
||||
{
|
||||
_writer.Write(value.Substring(start, length));
|
||||
}
|
||||
|
||||
Apply(match.Groups[1].Value);
|
||||
|
||||
start = match.Index + match.Length;
|
||||
}
|
||||
|
||||
if (start != value.Length)
|
||||
{
|
||||
_writer.Write(value.Substring(start));
|
||||
}
|
||||
}
|
||||
|
||||
private static void Apply(string parameter)
|
||||
{
|
||||
switch (parameter)
|
||||
{
|
||||
case "1":
|
||||
ApplyBold();
|
||||
break;
|
||||
|
||||
case "22":
|
||||
ResetBold();
|
||||
break;
|
||||
|
||||
case "30":
|
||||
ApplyColor(ConsoleColor.Black);
|
||||
break;
|
||||
|
||||
case "31":
|
||||
ApplyColor(ConsoleColor.DarkRed);
|
||||
break;
|
||||
|
||||
case "32":
|
||||
ApplyColor(ConsoleColor.DarkGreen);
|
||||
break;
|
||||
|
||||
case "33":
|
||||
ApplyColor(ConsoleColor.DarkYellow);
|
||||
break;
|
||||
|
||||
case "34":
|
||||
ApplyColor(ConsoleColor.DarkBlue);
|
||||
break;
|
||||
|
||||
case "35":
|
||||
ApplyColor(ConsoleColor.DarkMagenta);
|
||||
break;
|
||||
|
||||
case "36":
|
||||
ApplyColor(ConsoleColor.DarkCyan);
|
||||
break;
|
||||
|
||||
case "37":
|
||||
ApplyColor(ConsoleColor.Gray);
|
||||
break;
|
||||
|
||||
case "39":
|
||||
ResetColor();
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.Fail("Unsupported parameter: " + parameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyBold()
|
||||
=> Console.ForegroundColor = (ConsoleColor)((int)Console.ForegroundColor | 8);
|
||||
|
||||
private static void ResetBold()
|
||||
=> Console.ForegroundColor = (ConsoleColor)((int)Console.ForegroundColor & 7);
|
||||
|
||||
private static void ApplyColor(ConsoleColor color)
|
||||
{
|
||||
var wasBold = ((int)Console.ForegroundColor & 8) != 0;
|
||||
|
||||
Console.ForegroundColor = color;
|
||||
|
||||
if (wasBold)
|
||||
{
|
||||
ApplyBold();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResetColor()
|
||||
{
|
||||
var wasBold = ((int)Console.ForegroundColor & 8) != 0;
|
||||
|
||||
Console.ResetColor();
|
||||
|
||||
if (wasBold)
|
||||
{
|
||||
ApplyBold();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// 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 JetBrains.Annotations
|
||||
{
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Method | AttributeTargets.Parameter |
|
||||
AttributeTargets.Property | AttributeTargets.Delegate |
|
||||
AttributeTargets.Field)]
|
||||
internal sealed class NotNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Method | AttributeTargets.Parameter |
|
||||
AttributeTargets.Property | AttributeTargets.Delegate |
|
||||
AttributeTargets.Field)]
|
||||
internal sealed class CanBeNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// 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 GetDocument
|
||||
{
|
||||
internal class CommandException : Exception
|
||||
{
|
||||
public CommandException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public CommandException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandArgument
|
||||
{
|
||||
public CommandArgument() => Values = new List<string>();
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<string> Values { get; private set; }
|
||||
public bool MultipleValues { get; set; }
|
||||
public string Value => Values.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,604 @@
|
|||
// 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandLineApplication
|
||||
{
|
||||
private enum ParseOptionResult
|
||||
{
|
||||
Succeeded,
|
||||
ShowHelp,
|
||||
ShowVersion,
|
||||
UnexpectedArgs,
|
||||
}
|
||||
|
||||
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
|
||||
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
|
||||
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
|
||||
private readonly bool _throwOnUnexpectedArg;
|
||||
|
||||
public CommandLineApplication(bool throwOnUnexpectedArg = true)
|
||||
{
|
||||
_throwOnUnexpectedArg = throwOnUnexpectedArg;
|
||||
Options = new List<CommandOption>();
|
||||
Arguments = new List<CommandArgument>();
|
||||
Commands = new List<CommandLineApplication>();
|
||||
RemainingArguments = new List<string>();
|
||||
Invoke = () => 0;
|
||||
}
|
||||
|
||||
public CommandLineApplication Parent { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string FullName { get; set; }
|
||||
public string Syntax { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<CommandOption> Options { get; private set; }
|
||||
public CommandOption OptionHelp { get; private set; }
|
||||
public CommandOption OptionVersion { get; private set; }
|
||||
public List<CommandArgument> Arguments { get; private set; }
|
||||
public List<string> RemainingArguments { get; private set; }
|
||||
public bool IsShowingInformation { get; protected set; } // Is showing help or version?
|
||||
public Func<int> Invoke { get; set; }
|
||||
public Func<string> LongVersionGetter { get; set; }
|
||||
public Func<string> ShortVersionGetter { get; set; }
|
||||
public List<CommandLineApplication> Commands { get; private set; }
|
||||
public bool HandleResponseFiles { get; set; }
|
||||
public bool AllowArgumentSeparator { get; set; }
|
||||
public bool HandleRemainingArguments { get; set; }
|
||||
public string ArgumentSeparatorHelpText { get; set; }
|
||||
|
||||
public CommandLineApplication Command(string name, bool throwOnUnexpectedArg = true)
|
||||
=> Command(name, _ => { }, throwOnUnexpectedArg);
|
||||
|
||||
public CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
|
||||
bool throwOnUnexpectedArg = true)
|
||||
{
|
||||
var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name, Parent = this };
|
||||
Commands.Add(command);
|
||||
configuration(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
public CommandOption Option(string template, string description, CommandOptionType optionType)
|
||||
=> Option(template, description, optionType, _ => { });
|
||||
|
||||
public CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration)
|
||||
{
|
||||
var option = new CommandOption(template, optionType) { Description = description };
|
||||
Options.Add(option);
|
||||
configuration(option);
|
||||
return option;
|
||||
}
|
||||
|
||||
public CommandArgument Argument(string name, string description, bool multipleValues = false)
|
||||
=> Argument(name, description, _ => { }, multipleValues);
|
||||
|
||||
public CommandArgument Argument(string name, string description, Action<CommandArgument> configuration, bool multipleValues = false)
|
||||
{
|
||||
var lastArg = Arguments.LastOrDefault();
|
||||
if (lastArg != null && lastArg.MultipleValues)
|
||||
{
|
||||
var message = string.Format("The last argument '{0}' accepts multiple values. No more argument can be added.",
|
||||
lastArg.Name);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
var argument = new CommandArgument { Name = name, Description = description, MultipleValues = multipleValues };
|
||||
Arguments.Add(argument);
|
||||
configuration(argument);
|
||||
return argument;
|
||||
}
|
||||
|
||||
public void OnExecute(Func<int> invoke) => Invoke = invoke;
|
||||
|
||||
public void OnExecute(Func<Task<int>> invoke) => Invoke = () => invoke().Result;
|
||||
|
||||
public int Execute(params string[] args)
|
||||
{
|
||||
var command = this;
|
||||
IEnumerator<CommandArgument> arguments = null;
|
||||
|
||||
if (HandleResponseFiles)
|
||||
{
|
||||
args = ExpandResponseFiles(args).ToArray();
|
||||
}
|
||||
|
||||
for (var index = 0; index < args.Length; index++)
|
||||
{
|
||||
var arg = args[index];
|
||||
|
||||
var isLongOption = arg.StartsWith("--");
|
||||
if (isLongOption || arg.StartsWith("-"))
|
||||
{
|
||||
var result = ParseOption(isLongOption, command, args, ref index, out var option);
|
||||
if (result == ParseOptionResult.ShowHelp)
|
||||
{
|
||||
command.ShowHelp();
|
||||
return 0;
|
||||
}
|
||||
else if (result == ParseOptionResult.ShowVersion)
|
||||
{
|
||||
command.ShowVersion();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var subcommand = ParseSubCommand(arg, command);
|
||||
if (subcommand != null)
|
||||
{
|
||||
command = subcommand;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arguments == null)
|
||||
{
|
||||
arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
|
||||
}
|
||||
|
||||
if (arguments.MoveNext())
|
||||
{
|
||||
arguments.Current.Values.Add(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return command.Invoke();
|
||||
}
|
||||
|
||||
private ParseOptionResult ParseOption(
|
||||
bool isLongOption,
|
||||
CommandLineApplication command,
|
||||
string[] args,
|
||||
ref int index,
|
||||
out CommandOption option)
|
||||
{
|
||||
option = null;
|
||||
var result = ParseOptionResult.Succeeded;
|
||||
var arg = args[index];
|
||||
|
||||
var optionPrefixLength = isLongOption ? 2 : 1;
|
||||
var optionComponents = arg.Substring(optionPrefixLength).Split(new[] { ':', '=' }, 2);
|
||||
var optionName = optionComponents[0];
|
||||
|
||||
if (isLongOption)
|
||||
{
|
||||
option = command.Options.SingleOrDefault(
|
||||
opt => string.Equals(opt.LongName, optionName, StringComparison.Ordinal));
|
||||
}
|
||||
else
|
||||
{
|
||||
option = command.Options.SingleOrDefault(
|
||||
opt => string.Equals(opt.ShortName, optionName, StringComparison.Ordinal));
|
||||
|
||||
if (option == null)
|
||||
{
|
||||
option = command.Options.SingleOrDefault(
|
||||
opt => string.Equals(opt.SymbolName, optionName, StringComparison.Ordinal));
|
||||
}
|
||||
}
|
||||
|
||||
if (option == null)
|
||||
{
|
||||
if (isLongOption && string.IsNullOrEmpty(optionName) &&
|
||||
!command._throwOnUnexpectedArg && AllowArgumentSeparator)
|
||||
{
|
||||
// a stand-alone "--" is the argument separator, so skip it and
|
||||
// handle the rest of the args as unexpected args
|
||||
index++;
|
||||
}
|
||||
|
||||
HandleUnexpectedArg(command, args, index, argTypeName: "option");
|
||||
result = ParseOptionResult.UnexpectedArgs;
|
||||
}
|
||||
else if (command.OptionHelp == option)
|
||||
{
|
||||
result = ParseOptionResult.ShowHelp;
|
||||
}
|
||||
else if (command.OptionVersion == option)
|
||||
{
|
||||
result = ParseOptionResult.ShowVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (optionComponents.Length == 2)
|
||||
{
|
||||
if (!option.TryParse(optionComponents[1]))
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(command,
|
||||
$"Unexpected value '{optionComponents[1]}' for option '{optionName}'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option.OptionType == CommandOptionType.NoValue ||
|
||||
option.OptionType == CommandOptionType.BoolValue)
|
||||
{
|
||||
// No value is needed for this option
|
||||
option.TryParse(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
index++;
|
||||
arg = args[index];
|
||||
if (!option.TryParse(arg))
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{optionName}'");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static CommandLineApplication ParseSubCommand(string arg, CommandLineApplication command)
|
||||
{
|
||||
foreach (var subcommand in command.Commands)
|
||||
{
|
||||
if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return subcommand;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper method that adds a help option
|
||||
public CommandOption HelpOption(string template)
|
||||
{
|
||||
// Help option is special because we stop parsing once we see it
|
||||
// So we store it separately for further use
|
||||
OptionHelp = Option(template, "Show help information", CommandOptionType.NoValue);
|
||||
|
||||
return OptionHelp;
|
||||
}
|
||||
|
||||
public CommandOption VersionOption(string template,
|
||||
string shortFormVersion,
|
||||
string longFormVersion = null)
|
||||
{
|
||||
if (longFormVersion == null)
|
||||
{
|
||||
return VersionOption(template, () => shortFormVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
return VersionOption(template, () => shortFormVersion, () => longFormVersion);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method that adds a version option
|
||||
public CommandOption VersionOption(string template,
|
||||
Func<string> shortFormVersionGetter,
|
||||
Func<string> longFormVersionGetter = null)
|
||||
{
|
||||
// Version option is special because we stop parsing once we see it
|
||||
// So we store it separately for further use
|
||||
OptionVersion = Option(template, "Show version information", CommandOptionType.NoValue);
|
||||
ShortVersionGetter = shortFormVersionGetter;
|
||||
LongVersionGetter = longFormVersionGetter ?? shortFormVersionGetter;
|
||||
|
||||
return OptionVersion;
|
||||
}
|
||||
|
||||
// Show short hint that reminds users to use help option
|
||||
public void ShowHint()
|
||||
{
|
||||
if (OptionHelp != null)
|
||||
{
|
||||
Console.WriteLine(string.Format("Specify --{0} for a list of available options and commands.", OptionHelp.LongName));
|
||||
}
|
||||
}
|
||||
|
||||
// Show full help
|
||||
public void ShowHelp(string commandName = null)
|
||||
{
|
||||
var headerBuilder = new StringBuilder("Usage:");
|
||||
var usagePrefixLength = headerBuilder.Length;
|
||||
for (var cmd = this; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
cmd.IsShowingInformation = true;
|
||||
if (cmd != this && cmd.Arguments.Any())
|
||||
{
|
||||
var args = string.Join(" ", cmd.Arguments.Select(arg => arg.Name));
|
||||
headerBuilder.Insert(usagePrefixLength, string.Format(" {0} {1}", cmd.Name, args));
|
||||
}
|
||||
else
|
||||
{
|
||||
headerBuilder.Insert(usagePrefixLength, string.Format(" {0}", cmd.Name));
|
||||
}
|
||||
}
|
||||
|
||||
CommandLineApplication target;
|
||||
|
||||
if (commandName == null || string.Equals(Name, commandName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
target = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
target = Commands.SingleOrDefault(cmd => string.Equals(cmd.Name, commandName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
headerBuilder.AppendFormat(" {0}", commandName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The command name is invalid so don't try to show help for something that doesn't exist
|
||||
target = this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var optionsBuilder = new StringBuilder();
|
||||
var commandsBuilder = new StringBuilder();
|
||||
var argumentsBuilder = new StringBuilder();
|
||||
var argumentSeparatorBuilder = new StringBuilder();
|
||||
|
||||
var maxArgLen = 0;
|
||||
for (var cmd = target; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
if (cmd.Arguments.Any())
|
||||
{
|
||||
if (cmd == target)
|
||||
{
|
||||
headerBuilder.Append(" [arguments]");
|
||||
}
|
||||
|
||||
if (argumentsBuilder.Length == 0)
|
||||
{
|
||||
argumentsBuilder.AppendLine();
|
||||
argumentsBuilder.AppendLine("Arguments:");
|
||||
}
|
||||
|
||||
maxArgLen = Math.Max(maxArgLen, MaxArgumentLength(cmd.Arguments));
|
||||
}
|
||||
}
|
||||
|
||||
for (var cmd = target; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
if (cmd.Arguments.Any())
|
||||
{
|
||||
var outputFormat = " {0}{1}";
|
||||
foreach (var arg in cmd.Arguments)
|
||||
{
|
||||
argumentsBuilder.AppendFormat(
|
||||
outputFormat,
|
||||
arg.Name.PadRight(maxArgLen + 2),
|
||||
arg.Description);
|
||||
argumentsBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target.Options.Any())
|
||||
{
|
||||
headerBuilder.Append(" [options]");
|
||||
|
||||
optionsBuilder.AppendLine();
|
||||
optionsBuilder.AppendLine("Options:");
|
||||
var maxOptLen = MaxOptionTemplateLength(target.Options);
|
||||
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxOptLen + 2);
|
||||
foreach (var opt in target.Options)
|
||||
{
|
||||
optionsBuilder.AppendFormat(outputFormat, opt.Template, opt.Description);
|
||||
optionsBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (target.Commands.Any())
|
||||
{
|
||||
headerBuilder.Append(" [command]");
|
||||
|
||||
commandsBuilder.AppendLine();
|
||||
commandsBuilder.AppendLine("Commands:");
|
||||
var maxCmdLen = MaxCommandLength(target.Commands);
|
||||
var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxCmdLen + 2);
|
||||
foreach (var cmd in target.Commands.OrderBy(c => c.Name))
|
||||
{
|
||||
commandsBuilder.AppendFormat(outputFormat, cmd.Name, cmd.Description);
|
||||
commandsBuilder.AppendLine();
|
||||
}
|
||||
|
||||
if (OptionHelp != null)
|
||||
{
|
||||
commandsBuilder.AppendLine();
|
||||
commandsBuilder.AppendFormat("Use \"{0} [command] --help\" for more information about a command.", Name);
|
||||
commandsBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (target.AllowArgumentSeparator || target.HandleRemainingArguments)
|
||||
{
|
||||
if (target.AllowArgumentSeparator)
|
||||
{
|
||||
headerBuilder.Append(" [[--] <arg>...]]");
|
||||
}
|
||||
else
|
||||
{
|
||||
headerBuilder.Append(" [args]");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(target.ArgumentSeparatorHelpText))
|
||||
{
|
||||
argumentSeparatorBuilder.AppendLine();
|
||||
argumentSeparatorBuilder.AppendLine("Args:");
|
||||
argumentSeparatorBuilder.AppendLine($" {target.ArgumentSeparatorHelpText}");
|
||||
argumentSeparatorBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
headerBuilder.AppendLine();
|
||||
|
||||
var nameAndVersion = new StringBuilder();
|
||||
nameAndVersion.AppendLine(GetFullNameAndVersion());
|
||||
nameAndVersion.AppendLine();
|
||||
|
||||
Console.Write("{0}{1}{2}{3}{4}{5}", nameAndVersion, headerBuilder, argumentsBuilder, optionsBuilder, commandsBuilder, argumentSeparatorBuilder);
|
||||
}
|
||||
|
||||
public void ShowVersion()
|
||||
{
|
||||
for (var cmd = this; cmd != null; cmd = cmd.Parent)
|
||||
{
|
||||
cmd.IsShowingInformation = true;
|
||||
}
|
||||
|
||||
Console.WriteLine(FullName);
|
||||
Console.WriteLine(LongVersionGetter());
|
||||
}
|
||||
|
||||
public string GetFullNameAndVersion()
|
||||
=> ShortVersionGetter == null ? FullName : string.Format("{0} {1}", FullName, ShortVersionGetter());
|
||||
|
||||
public void ShowRootCommandFullNameAndVersion()
|
||||
{
|
||||
var rootCmd = this;
|
||||
while (rootCmd.Parent != null)
|
||||
{
|
||||
rootCmd = rootCmd.Parent;
|
||||
}
|
||||
|
||||
Console.WriteLine(rootCmd.GetFullNameAndVersion());
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static int MaxOptionTemplateLength(IEnumerable<CommandOption> options)
|
||||
{
|
||||
var maxLen = 0;
|
||||
foreach (var opt in options)
|
||||
{
|
||||
maxLen = opt.Template.Length > maxLen ? opt.Template.Length : maxLen;
|
||||
}
|
||||
return maxLen;
|
||||
}
|
||||
|
||||
private static int MaxCommandLength(IEnumerable<CommandLineApplication> commands)
|
||||
{
|
||||
var maxLen = 0;
|
||||
foreach (var cmd in commands)
|
||||
{
|
||||
maxLen = cmd.Name.Length > maxLen ? cmd.Name.Length : maxLen;
|
||||
}
|
||||
return maxLen;
|
||||
}
|
||||
|
||||
private static int MaxArgumentLength(IEnumerable<CommandArgument> arguments)
|
||||
{
|
||||
var maxLen = 0;
|
||||
foreach (var arg in arguments)
|
||||
{
|
||||
maxLen = arg.Name.Length > maxLen ? arg.Name.Length : maxLen;
|
||||
}
|
||||
return maxLen;
|
||||
}
|
||||
|
||||
private static void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName)
|
||||
{
|
||||
if (command._throwOnUnexpectedArg)
|
||||
{
|
||||
command.ShowHint();
|
||||
throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
command.RemainingArguments.Add(args[index]);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> ExpandResponseFiles(IEnumerable<string> args)
|
||||
{
|
||||
foreach (var arg in args)
|
||||
{
|
||||
if (!arg.StartsWith("@", StringComparison.Ordinal))
|
||||
{
|
||||
yield return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileName = arg.Substring(1);
|
||||
|
||||
var responseFileArguments = ParseResponseFile(fileName);
|
||||
|
||||
// ParseResponseFile can suppress expanding this response file by
|
||||
// returning null. In that case, we'll treat the response
|
||||
// file token as a regular argument.
|
||||
|
||||
if (responseFileArguments == null)
|
||||
{
|
||||
yield return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var responseFileArgument in responseFileArguments)
|
||||
{
|
||||
yield return responseFileArgument.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> ParseResponseFile(string fileName)
|
||||
{
|
||||
if (!HandleResponseFiles)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
throw new InvalidOperationException($"Response file '{fileName}' doesn't exist.");
|
||||
}
|
||||
|
||||
return File.ReadLines(fileName);
|
||||
}
|
||||
|
||||
private class CommandArgumentEnumerator : IEnumerator<CommandArgument>
|
||||
{
|
||||
private readonly IEnumerator<CommandArgument> _enumerator;
|
||||
|
||||
public CommandArgumentEnumerator(IEnumerator<CommandArgument> enumerator) => _enumerator = enumerator;
|
||||
|
||||
public CommandArgument Current => _enumerator.Current;
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public void Dispose() => _enumerator.Dispose();
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (Current == null || !Current.MultipleValues)
|
||||
{
|
||||
return _enumerator.MoveNext();
|
||||
}
|
||||
|
||||
// If current argument allows multiple values, we don't move forward and
|
||||
// all later values will be added to current CommandArgument.Values
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset() => _enumerator.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal static class CommandLineApplicationExtensions
|
||||
{
|
||||
public static CommandOption Option(this CommandLineApplication command, string template, string description)
|
||||
=> command.Option(
|
||||
template,
|
||||
description,
|
||||
template.IndexOf('<') != -1
|
||||
? template.EndsWith(">...")
|
||||
? CommandOptionType.MultipleValue
|
||||
: CommandOptionType.SingleValue
|
||||
: CommandOptionType.NoValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandOption
|
||||
{
|
||||
public CommandOption(string template, CommandOptionType optionType)
|
||||
{
|
||||
Template = template;
|
||||
OptionType = optionType;
|
||||
Values = new List<string>();
|
||||
|
||||
foreach (var part in Template.Split(new[] { ' ', '|' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (part.StartsWith("--"))
|
||||
{
|
||||
LongName = part.Substring(2);
|
||||
}
|
||||
else if (part.StartsWith("-"))
|
||||
{
|
||||
var optName = part.Substring(1);
|
||||
|
||||
// If there is only one char and it is not an English letter, it is a symbol option (e.g. "-?")
|
||||
if (optName.Length == 1 && !IsEnglishLetter(optName[0]))
|
||||
{
|
||||
SymbolName = optName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShortName = optName;
|
||||
}
|
||||
}
|
||||
else if (part.StartsWith("<") && part.EndsWith(">"))
|
||||
{
|
||||
ValueName = part.Substring(1, part.Length - 2);
|
||||
}
|
||||
else if (optionType == CommandOptionType.MultipleValue && part.StartsWith("<") && part.EndsWith(">..."))
|
||||
{
|
||||
ValueName = part.Substring(1, part.Length - 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(LongName) && string.IsNullOrEmpty(ShortName) && string.IsNullOrEmpty(SymbolName))
|
||||
{
|
||||
throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
|
||||
}
|
||||
}
|
||||
|
||||
public string Template { get; set; }
|
||||
public string ShortName { get; set; }
|
||||
public string LongName { get; set; }
|
||||
public string SymbolName { get; set; }
|
||||
public string ValueName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public List<string> Values { get; private set; }
|
||||
public bool? BoolValue { get; private set; }
|
||||
public CommandOptionType OptionType { get; private set; }
|
||||
|
||||
public bool TryParse(string value)
|
||||
{
|
||||
switch (OptionType)
|
||||
{
|
||||
case CommandOptionType.MultipleValue:
|
||||
Values.Add(value);
|
||||
break;
|
||||
case CommandOptionType.SingleValue:
|
||||
if (Values.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Values.Add(value);
|
||||
break;
|
||||
case CommandOptionType.BoolValue:
|
||||
if (Values.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
// add null to indicate that the option was present, but had no value
|
||||
Values.Add(null);
|
||||
BoolValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bool.TryParse(value, out var boolValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Values.Add(value);
|
||||
BoolValue = boolValue;
|
||||
}
|
||||
break;
|
||||
case CommandOptionType.NoValue:
|
||||
if (value != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Add a value to indicate that this option was specified
|
||||
Values.Add("on");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasValue() => Values.Any();
|
||||
|
||||
public string Value() => HasValue() ? Values[0] : null;
|
||||
|
||||
private static bool IsEnglishLetter(char c) => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal enum CommandOptionType
|
||||
{
|
||||
MultipleValue,
|
||||
SingleValue,
|
||||
BoolValue,
|
||||
NoValue
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// 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.DotNet.Cli.CommandLine
|
||||
{
|
||||
internal class CommandParsingException : Exception
|
||||
{
|
||||
public CommandParsingException(CommandLineApplication command, string message)
|
||||
: base(message) => Command = command;
|
||||
|
||||
public CommandLineApplication Command { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// 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 GetDocument.Properties;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument.Commands
|
||||
{
|
||||
internal abstract class CommandBase
|
||||
{
|
||||
public virtual void Configure(CommandLineApplication command)
|
||||
{
|
||||
var verbose = command.Option("-v|--verbose", Resources.VerboseDescription);
|
||||
var noColor = command.Option("--no-color", Resources.NoColorDescription);
|
||||
var prefixOutput = command.Option("--prefix-output", Resources.PrefixDescription);
|
||||
|
||||
command.HandleResponseFiles = true;
|
||||
|
||||
command.OnExecute(
|
||||
() =>
|
||||
{
|
||||
Reporter.IsVerbose = verbose.HasValue();
|
||||
Reporter.NoColor = noColor.HasValue();
|
||||
Reporter.PrefixOutput = prefixOutput.HasValue();
|
||||
|
||||
Validate();
|
||||
|
||||
return Execute();
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual void Validate()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual int Execute()
|
||||
=> 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
#if NETCOREAPP2_0
|
||||
using System.Runtime.Loader;
|
||||
#endif
|
||||
using GetDocument.Properties;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument.Commands
|
||||
{
|
||||
internal class GetDocumentCommand : ProjectCommandBase
|
||||
{
|
||||
internal const string FallbackDocumentName = "v1";
|
||||
internal const string FallbackMethod = "Generate";
|
||||
internal const string FallbackService = "Microsoft.Extensions.ApiDescription.IDocumentProvider";
|
||||
private const string WorkerType = "GetDocument.Commands.GetDocumentCommandWorker";
|
||||
|
||||
private CommandOption _documentName;
|
||||
private CommandOption _method;
|
||||
private CommandOption _output;
|
||||
private CommandOption _service;
|
||||
private CommandOption _uri;
|
||||
|
||||
public override void Configure(CommandLineApplication command)
|
||||
{
|
||||
base.Configure(command);
|
||||
|
||||
_documentName = command.Option(
|
||||
"--documentName <Name>",
|
||||
Resources.DocumentDescription(FallbackDocumentName));
|
||||
_method = command.Option("--method <Name>", Resources.MethodDescription(FallbackMethod));
|
||||
_output = command.Option("--output <Path>", Resources.OutputDescription);
|
||||
_service = command.Option("--service <QualifiedName>", Resources.ServiceDescription(FallbackService));
|
||||
_uri = command.Option("--uri <URI>", Resources.UriDescription);
|
||||
}
|
||||
|
||||
protected override void Validate()
|
||||
{
|
||||
base.Validate();
|
||||
|
||||
if (!_output.HasValue())
|
||||
{
|
||||
throw new CommandException(Resources.MissingOption(_output.LongName));
|
||||
}
|
||||
|
||||
if (_method.HasValue() && !_service.HasValue())
|
||||
{
|
||||
throw new CommandException(Resources.MissingOption(_service.LongName));
|
||||
}
|
||||
|
||||
if (_service.HasValue() && !_method.HasValue())
|
||||
{
|
||||
throw new CommandException(Resources.MissingOption(_method.LongName));
|
||||
}
|
||||
}
|
||||
|
||||
protected override int Execute()
|
||||
{
|
||||
var thisAssembly = typeof(GetDocumentCommand).Assembly;
|
||||
|
||||
var toolsDirectory = ToolsDirectory.Value();
|
||||
var packagedAssemblies = Directory
|
||||
.EnumerateFiles(toolsDirectory, "*.dll")
|
||||
.Except(new[] { Path.GetFullPath(thisAssembly.Location) })
|
||||
.ToDictionary(path => Path.GetFileNameWithoutExtension(path), path => new AssemblyInfo(path));
|
||||
|
||||
// Explicitly load all assemblies we need first to preserve target project as much as possible. This
|
||||
// executable is always run in the target project's context (either through location or .deps.json file).
|
||||
foreach (var keyValuePair in packagedAssemblies)
|
||||
{
|
||||
try
|
||||
{
|
||||
keyValuePair.Value.Assembly = Assembly.Load(new AssemblyName(keyValuePair.Key));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore all failures because missing assemblies should be loadable from tools directory.
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_0
|
||||
AssemblyLoadContext.Default.Resolving += (loadContext, assemblyName) =>
|
||||
{
|
||||
var name = assemblyName.Name;
|
||||
if (!packagedAssemblies.TryGetValue(name, out var info))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var assemblyPath = info.Path;
|
||||
if (!File.Exists(assemblyPath))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Referenced assembly '{name}' was not found in '{toolsDirectory}'.");
|
||||
}
|
||||
|
||||
return loadContext.LoadFromAssemblyPath(assemblyPath);
|
||||
};
|
||||
|
||||
#elif NET461
|
||||
AppDomain.CurrentDomain.AssemblyResolve += (source, eventArgs) =>
|
||||
{
|
||||
var assemblyName = new AssemblyName(eventArgs.Name);
|
||||
var name = assemblyName.Name;
|
||||
if (!packagedAssemblies.TryGetValue(name, out var info))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var assembly = info.Assembly;
|
||||
if (assembly != null)
|
||||
{
|
||||
// Loaded already
|
||||
return assembly;
|
||||
}
|
||||
|
||||
var assemblyPath = info.Path;
|
||||
if (!File.Exists(assemblyPath))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Referenced assembly '{name}' was not found in '{toolsDirectory}'.");
|
||||
}
|
||||
|
||||
return Assembly.LoadFile(assemblyPath);
|
||||
};
|
||||
#else
|
||||
#error target frameworks need to be updated.
|
||||
#endif
|
||||
|
||||
// Now safe to reference TestHost type.
|
||||
try
|
||||
{
|
||||
var workerType = thisAssembly.GetType(WorkerType, throwOnError: true);
|
||||
var methodInfo = workerType.GetMethod("Process", BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
var assemblyPath = AssemblyPath.Value();
|
||||
var context = new GetDocumentCommandContext
|
||||
{
|
||||
AssemblyPath = assemblyPath,
|
||||
AssemblyDirectory = Path.GetDirectoryName(assemblyPath),
|
||||
AssemblyName = Path.GetFileNameWithoutExtension(assemblyPath),
|
||||
DocumentName = _documentName.Value(),
|
||||
Method = _method.Value(),
|
||||
Output = _output.Value(),
|
||||
Service = _service.Value(),
|
||||
Uri = _uri.Value(),
|
||||
};
|
||||
|
||||
return (int)methodInfo.Invoke(obj: null, parameters: new[] { context });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine(ex.ToString());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private class AssemblyInfo
|
||||
{
|
||||
public AssemblyInfo(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public Assembly Assembly { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
|
||||
namespace GetDocument.Commands
|
||||
{
|
||||
[Serializable]
|
||||
public class GetDocumentCommandContext
|
||||
{
|
||||
public string AssemblyDirectory { get; set; }
|
||||
|
||||
public string AssemblyName { get; set; }
|
||||
|
||||
public string AssemblyPath { get; set; }
|
||||
|
||||
public string DocumentName { get; set; }
|
||||
|
||||
public string Method { get; set; }
|
||||
|
||||
public string Output { get; set; }
|
||||
|
||||
public string Service { get; set; }
|
||||
|
||||
public string Uri { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GenerationTasks;
|
||||
using GetDocument.Properties;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace GetDocument.Commands
|
||||
{
|
||||
internal class GetDocumentCommandWorker
|
||||
{
|
||||
public static int Process(GetDocumentCommandContext context)
|
||||
{
|
||||
var assemblyName = new AssemblyName(context.AssemblyName);
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
var entryPointType = assembly.EntryPoint?.DeclaringType;
|
||||
if (entryPointType == null)
|
||||
{
|
||||
Reporter.WriteError(Resources.MissingEntryPoint(context.AssemblyPath));
|
||||
return 2;
|
||||
}
|
||||
|
||||
var services = GetServices(entryPointType, context.AssemblyPath, context.AssemblyName);
|
||||
if (services == null)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
var success = TryProcess(context, services);
|
||||
if (!success && string.IsNullOrEmpty(context.Uri))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
var builder = GetBuilder(entryPointType, context.AssemblyPath, context.AssemblyName);
|
||||
if (builder == null)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
// Mute the HttpsRedirectionMiddleware warning about HTTPS configuration.
|
||||
builder.ConfigureLogging(loggingBuilder => loggingBuilder.AddFilter(
|
||||
"Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware",
|
||||
LogLevel.Error));
|
||||
|
||||
using (var server = new TestServer(builder))
|
||||
{
|
||||
ProcessAsync(context, server).Wait();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool TryProcess(GetDocumentCommandContext context, IServiceProvider services)
|
||||
{
|
||||
var documentName = string.IsNullOrEmpty(context.DocumentName) ?
|
||||
GetDocumentCommand.FallbackDocumentName :
|
||||
context.DocumentName;
|
||||
var methodName = string.IsNullOrEmpty(context.Method) ?
|
||||
GetDocumentCommand.FallbackMethod :
|
||||
context.Method;
|
||||
var serviceName = string.IsNullOrEmpty(context.Service) ?
|
||||
GetDocumentCommand.FallbackService :
|
||||
context.Service;
|
||||
|
||||
Reporter.WriteInformation(Resources.UsingDocument(documentName));
|
||||
Reporter.WriteInformation(Resources.UsingMethod(methodName));
|
||||
Reporter.WriteInformation(Resources.UsingService(serviceName));
|
||||
|
||||
try
|
||||
{
|
||||
var serviceType = Type.GetType(serviceName, throwOnError: true);
|
||||
var method = serviceType.GetMethod(methodName, new[] { typeof(TextWriter), typeof(string) });
|
||||
var service = services.GetRequiredService(serviceType);
|
||||
|
||||
var success = true;
|
||||
using (var writer = File.CreateText(context.Output))
|
||||
{
|
||||
if (method.ReturnType == typeof(bool))
|
||||
{
|
||||
success = (bool)method.Invoke(service, new object[] { writer, documentName });
|
||||
}
|
||||
else
|
||||
{
|
||||
method.Invoke(service, new object[] { writer, documentName });
|
||||
}
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
var message = Resources.MethodInvocationFailed(methodName, serviceName, documentName);
|
||||
if (string.IsNullOrEmpty(context.Uri) && !File.Exists(context.Output))
|
||||
{
|
||||
Reporter.WriteError(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reporter.WriteWarning(message);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var message = FormatException(ex);
|
||||
if (string.IsNullOrEmpty(context.Uri) && !File.Exists(context.Output))
|
||||
{
|
||||
Reporter.WriteError(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reporter.WriteWarning(message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ProcessAsync(GetDocumentCommandContext context, TestServer server)
|
||||
{
|
||||
|
||||
Debug.Assert(!string.IsNullOrEmpty(context.Uri));
|
||||
Reporter.WriteInformation(Resources.UsingUri(context.Uri));
|
||||
|
||||
var httpClient = server.CreateClient();
|
||||
await DownloadFileCore.DownloadAsync(
|
||||
context.Uri,
|
||||
context.Output,
|
||||
httpClient,
|
||||
new LogWrapper(),
|
||||
CancellationToken.None,
|
||||
timeoutSeconds: 60);
|
||||
}
|
||||
|
||||
// TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available.
|
||||
private static IServiceProvider GetServices(Type entryPointType, string assemblyPath, string assemblyName)
|
||||
{
|
||||
var args = new[] { Array.Empty<string>() };
|
||||
var methodInfo = entryPointType.GetMethod("BuildWebHost");
|
||||
if (methodInfo != null)
|
||||
{
|
||||
// BuildWebHost (old style has highest priority)
|
||||
var parameters = methodInfo.GetParameters();
|
||||
if (!methodInfo.IsStatic ||
|
||||
parameters.Length != 1 ||
|
||||
typeof(string[]) != parameters[0].ParameterType ||
|
||||
typeof(IWebHost) != methodInfo.ReturnType)
|
||||
{
|
||||
Reporter.WriteError(
|
||||
"BuildWebHost method found in {assemblyPath} does not have expected signature.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var webHost = (IWebHost)methodInfo.Invoke(obj: null, parameters: args);
|
||||
|
||||
return webHost.Services;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Reporter.WriteError($"BuildWebHost method threw: {FormatException(ex)}");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ((methodInfo = entryPointType.GetMethod("CreateWebHostBuilder")) != null)
|
||||
{
|
||||
// CreateWebHostBuilder
|
||||
var parameters = methodInfo.GetParameters();
|
||||
if (!methodInfo.IsStatic ||
|
||||
parameters.Length != 1 ||
|
||||
typeof(string[]) != parameters[0].ParameterType ||
|
||||
typeof(IWebHostBuilder) != methodInfo.ReturnType)
|
||||
{
|
||||
Reporter.WriteError(
|
||||
"CreateWebHostBuilder method found in {assemblyPath} does not have expected signature.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var builder = (IWebHostBuilder)methodInfo.Invoke(obj: null, parameters: args);
|
||||
|
||||
return builder.Build().Services;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Reporter.WriteError($"CreateWebHostBuilder method threw: {FormatException(ex)}");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Startup
|
||||
return new WebHostBuilder().UseStartup(assemblyName).Build().Services;
|
||||
}
|
||||
|
||||
// TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available.
|
||||
private static IWebHostBuilder GetBuilder(Type entryPointType, string assemblyPath, string assemblyName)
|
||||
{
|
||||
var methodInfo = entryPointType.GetMethod("BuildWebHost");
|
||||
if (methodInfo != null)
|
||||
{
|
||||
// BuildWebHost cannot be used. Fall through, most likely to Startup fallback.
|
||||
Reporter.WriteWarning(
|
||||
"BuildWebHost method cannot be used. Falling back to minimal Startup configuration.");
|
||||
}
|
||||
|
||||
methodInfo = entryPointType.GetMethod("CreateWebHostBuilder");
|
||||
if (methodInfo != null)
|
||||
{
|
||||
// CreateWebHostBuilder
|
||||
var parameters = methodInfo.GetParameters();
|
||||
if (!methodInfo.IsStatic ||
|
||||
parameters.Length != 1 ||
|
||||
typeof(string[]) != parameters[0].ParameterType ||
|
||||
typeof(IWebHostBuilder) != methodInfo.ReturnType)
|
||||
{
|
||||
Reporter.WriteError(
|
||||
"CreateWebHostBuilder method found in {assemblyPath} does not have expected signature.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var args = new[] { Array.Empty<string>() };
|
||||
var builder = (IWebHostBuilder)methodInfo.Invoke(obj: null, parameters: args);
|
||||
|
||||
return builder;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Reporter.WriteError($"CreateWebHostBuilder method threw: {FormatException(ex)}");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Startup
|
||||
return new WebHostBuilder().UseStartup(assemblyName);
|
||||
}
|
||||
|
||||
private static string FormatException(Exception exception)
|
||||
{
|
||||
return $"{exception.GetType().FullName}: {exception.Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// 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.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument.Commands
|
||||
{
|
||||
internal class HelpCommandBase : CommandBase
|
||||
{
|
||||
public override void Configure(CommandLineApplication command)
|
||||
{
|
||||
base.Configure(command);
|
||||
|
||||
command.HelpOption("-h|--help");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// 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 GetDocument.Properties;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument.Commands
|
||||
{
|
||||
internal abstract class ProjectCommandBase : HelpCommandBase
|
||||
{
|
||||
public CommandOption AssemblyPath { get; private set; }
|
||||
|
||||
public CommandOption ToolsDirectory { get; private set; }
|
||||
|
||||
public override void Configure(CommandLineApplication command)
|
||||
{
|
||||
base.Configure(command);
|
||||
|
||||
AssemblyPath = command.Option("-a|--assembly <PATH>", Resources.AssemblyDescription);
|
||||
ToolsDirectory = command.Option("--tools-directory <PATH>", Resources.ToolsDirectoryDescription);
|
||||
}
|
||||
|
||||
protected override void Validate()
|
||||
{
|
||||
base.Validate();
|
||||
|
||||
if (!AssemblyPath.HasValue())
|
||||
{
|
||||
throw new CommandException(Resources.MissingOption(AssemblyPath.LongName));
|
||||
}
|
||||
|
||||
if (!ToolsDirectory.HasValue())
|
||||
{
|
||||
throw new CommandException(Resources.MissingOption(ToolsDirectory.LongName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AssemblyName>GetDocument.Insider</AssemblyName>
|
||||
<Description>GetDocument Command-line Tool inside man</Description>
|
||||
<IsPackable>false</IsPackable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>GetDocument</RootNamespace>
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="../Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs" />
|
||||
<Compile Include="../Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="$(MicrosoftAspNetCoreTestHost20PackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Properties/Resources.Designer.tt">
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties/Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.Designer.tt</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// 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 GetDocument.Properties;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal static class Json
|
||||
{
|
||||
public static CommandOption ConfigureOption(CommandLineApplication command)
|
||||
=> command.Option("--json", Resources.JsonDescription);
|
||||
|
||||
public static string Literal(string text)
|
||||
=> text != null
|
||||
? "\"" + text.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""
|
||||
: "null";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using GenerationTasks;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
public class LogWrapper : ILogWrapper
|
||||
{
|
||||
public void LogError(string message, params object[] messageArgs)
|
||||
{
|
||||
Reporter.WriteError(string.Format(message, messageArgs));
|
||||
}
|
||||
|
||||
public void LogError(Exception exception, bool showStackTrace)
|
||||
{
|
||||
var message = showStackTrace ? exception.ToString() : exception.Message;
|
||||
Reporter.WriteError(message);
|
||||
}
|
||||
|
||||
public void LogInformational(string message, params object[] messageArgs)
|
||||
{
|
||||
Reporter.WriteInformation(string.Format(message, messageArgs));
|
||||
}
|
||||
|
||||
public void LogWarning(string message, params object[] messageArgs)
|
||||
{
|
||||
Reporter.WriteWarning(string.Format(message, messageArgs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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.Reflection;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the GetDocument infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public static class ProductInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the GetDocument infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
public static string GetVersion()
|
||||
=> typeof(ProductInfo)
|
||||
.Assembly
|
||||
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
|
||||
.InformationalVersion;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// 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.Text;
|
||||
using GetDocument.Commands;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static int Main(string[] args)
|
||||
{
|
||||
if (Console.IsOutputRedirected)
|
||||
{
|
||||
Console.OutputEncoding = Encoding.UTF8;
|
||||
}
|
||||
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false)
|
||||
{
|
||||
Name = "GetDocument.Insider"
|
||||
};
|
||||
|
||||
new GetDocumentCommand().Configure(app);
|
||||
|
||||
try
|
||||
{
|
||||
return app.Execute(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is CommandException
|
||||
|| ex is CommandParsingException
|
||||
|| (ex is WrappedException wrappedException
|
||||
&& wrappedException.Type == "GetDocument.Design.OperationException"))
|
||||
{
|
||||
Reporter.WriteVerbose(ex.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Reporter.WriteInformation(ex.ToString());
|
||||
}
|
||||
|
||||
Reporter.WriteError(ex.Message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
// <auto-generated />
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace GetDocument.Properties
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the GetDocument infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("GetDocument.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The assembly to use.
|
||||
/// </summary>
|
||||
public static string AssemblyDescription
|
||||
=> GetString("AssemblyDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Show JSON output.
|
||||
/// </summary>
|
||||
public static string JsonDescription
|
||||
=> GetString("JsonDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Missing required option '--{option}'.
|
||||
/// </summary>
|
||||
public static string MissingOption([CanBeNull] object option)
|
||||
=> string.Format(
|
||||
GetString("MissingOption", nameof(option)),
|
||||
option);
|
||||
|
||||
/// <summary>
|
||||
/// Do not colorize output.
|
||||
/// </summary>
|
||||
public static string NoColorDescription
|
||||
=> GetString("NoColorDescription");
|
||||
|
||||
/// <summary>
|
||||
/// The file to write the result to.
|
||||
/// </summary>
|
||||
public static string OutputDescription
|
||||
=> GetString("OutputDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Prefix console output with logging level.
|
||||
/// </summary>
|
||||
public static string PrefixDescription
|
||||
=> GetString("PrefixDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Using application base '{appBase}'.
|
||||
/// </summary>
|
||||
public static string UsingApplicationBase([CanBeNull] object appBase)
|
||||
=> string.Format(
|
||||
GetString("UsingApplicationBase", nameof(appBase)),
|
||||
appBase);
|
||||
|
||||
/// <summary>
|
||||
/// Using assembly '{assembly}'.
|
||||
/// </summary>
|
||||
public static string UsingAssembly([CanBeNull] object assembly)
|
||||
=> string.Format(
|
||||
GetString("UsingAssembly", nameof(assembly)),
|
||||
assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Using configuration file '{config}'.
|
||||
/// </summary>
|
||||
public static string UsingConfigurationFile([CanBeNull] object config)
|
||||
=> string.Format(
|
||||
GetString("UsingConfigurationFile", nameof(config)),
|
||||
config);
|
||||
|
||||
/// <summary>
|
||||
/// Show verbose output.
|
||||
/// </summary>
|
||||
public static string VerboseDescription
|
||||
=> GetString("VerboseDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Writing '{file}'...
|
||||
/// </summary>
|
||||
public static string WritingFile([CanBeNull] object file)
|
||||
=> string.Format(
|
||||
GetString("WritingFile", nameof(file)),
|
||||
file);
|
||||
|
||||
/// <summary>
|
||||
/// Using working directory '{workingDirectory}'.
|
||||
/// </summary>
|
||||
public static string UsingWorkingDirectory([CanBeNull] object workingDirectory)
|
||||
=> string.Format(
|
||||
GetString("UsingWorkingDirectory", nameof(workingDirectory)),
|
||||
workingDirectory);
|
||||
|
||||
/// <summary>
|
||||
/// Location from which inside man was copied (in the .NET Framework case) or loaded.
|
||||
/// </summary>
|
||||
public static string ToolsDirectoryDescription
|
||||
=> GetString("ToolsDirectoryDescription");
|
||||
|
||||
/// <summary>
|
||||
/// The URI to download the document from.
|
||||
/// </summary>
|
||||
public static string UriDescription
|
||||
=> GetString("UriDescription");
|
||||
|
||||
/// <summary>
|
||||
/// The name of the method to invoke on the '--service' instance. Default value '{defaultMethod}'.
|
||||
/// </summary>
|
||||
public static string MethodDescription([CanBeNull] object defaultMethod)
|
||||
=> string.Format(
|
||||
GetString("MethodDescription", nameof(defaultMethod)),
|
||||
defaultMethod);
|
||||
|
||||
/// <summary>
|
||||
/// The qualified name of the service type to retrieve from dependency injection. Default value '{defaultService}'.
|
||||
/// </summary>
|
||||
public static string ServiceDescription([CanBeNull] object defaultService)
|
||||
=> string.Format(
|
||||
GetString("ServiceDescription", nameof(defaultService)),
|
||||
defaultService);
|
||||
|
||||
/// <summary>
|
||||
/// Missing required option '--{option1}' or '--{option2}'.
|
||||
/// </summary>
|
||||
public static string MissingOptions([CanBeNull] object option1, [CanBeNull] object option2)
|
||||
=> string.Format(
|
||||
GetString("MissingOptions", nameof(option1), nameof(option2)),
|
||||
option1, option2);
|
||||
|
||||
/// <summary>
|
||||
/// The name of the document to pass to the '--method' method. Default value '{defaultDocumentName}'.
|
||||
/// </summary>
|
||||
public static string DocumentDescription([CanBeNull] object defaultDocumentName)
|
||||
=> string.Format(
|
||||
GetString("DocumentDescription", nameof(defaultDocumentName)),
|
||||
defaultDocumentName);
|
||||
|
||||
/// <summary>
|
||||
/// Using document name '{documentName}'.
|
||||
/// </summary>
|
||||
public static string UsingDocument([CanBeNull] object documentName)
|
||||
=> string.Format(
|
||||
GetString("UsingDocument", nameof(documentName)),
|
||||
documentName);
|
||||
|
||||
/// <summary>
|
||||
/// Using method '{method}'.
|
||||
/// </summary>
|
||||
public static string UsingMethod([CanBeNull] object method)
|
||||
=> string.Format(
|
||||
GetString("UsingMethod", nameof(method)),
|
||||
method);
|
||||
|
||||
/// <summary>
|
||||
/// Using service '{service}'.
|
||||
/// </summary>
|
||||
public static string UsingService([CanBeNull] object service)
|
||||
=> string.Format(
|
||||
GetString("UsingService", nameof(service)),
|
||||
service);
|
||||
|
||||
/// <summary>
|
||||
/// Using URI '{uri}'.
|
||||
/// </summary>
|
||||
public static string UsingUri([CanBeNull] object uri)
|
||||
=> string.Format(
|
||||
GetString("UsingUri", nameof(uri)),
|
||||
uri);
|
||||
|
||||
/// <summary>
|
||||
/// Method '{method}' of service '{service}' failed to generate document '{documentName}'.
|
||||
/// </summary>
|
||||
public static string MethodInvocationFailed([CanBeNull] object method, [CanBeNull] object service, [CanBeNull] object documentName)
|
||||
=> string.Format(
|
||||
GetString("MethodInvocationFailed", nameof(method), nameof(service), nameof(documentName)),
|
||||
method, service, documentName);
|
||||
|
||||
/// <summary>
|
||||
/// Assembly '{assemblyPath}' does not contain an entry point.
|
||||
/// </summary>
|
||||
public static string MissingEntryPoint([CanBeNull] object assemblyPath)
|
||||
=> string.Format(
|
||||
GetString("MissingEntryPoint", nameof(assemblyPath)),
|
||||
assemblyPath);
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<#
|
||||
Session["ResourceFile"] = "Resources.resx";
|
||||
Session["AccessModifier"] = "internal";
|
||||
Session["NoDiagnostics"] = true;
|
||||
#>
|
||||
<#@ include file="..\..\tools\Resources.tt" #>
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="AssemblyDescription" xml:space="preserve">
|
||||
<value>The assembly to use.</value>
|
||||
</data>
|
||||
<data name="JsonDescription" xml:space="preserve">
|
||||
<value>Show JSON output.</value>
|
||||
</data>
|
||||
<data name="MissingOption" xml:space="preserve">
|
||||
<value>Missing required option '--{option}'.</value>
|
||||
</data>
|
||||
<data name="NoColorDescription" xml:space="preserve">
|
||||
<value>Do not colorize output.</value>
|
||||
</data>
|
||||
<data name="OutputDescription" xml:space="preserve">
|
||||
<value>The file to write the result to.</value>
|
||||
</data>
|
||||
<data name="PrefixDescription" xml:space="preserve">
|
||||
<value>Prefix console output with logging level.</value>
|
||||
</data>
|
||||
<data name="UsingApplicationBase" xml:space="preserve">
|
||||
<value>Using application base '{appBase}'.</value>
|
||||
</data>
|
||||
<data name="UsingAssembly" xml:space="preserve">
|
||||
<value>Using assembly '{assembly}'.</value>
|
||||
</data>
|
||||
<data name="UsingConfigurationFile" xml:space="preserve">
|
||||
<value>Using configuration file '{config}'.</value>
|
||||
</data>
|
||||
<data name="VerboseDescription" xml:space="preserve">
|
||||
<value>Show verbose output.</value>
|
||||
</data>
|
||||
<data name="WritingFile" xml:space="preserve">
|
||||
<value>Writing '{file}'...</value>
|
||||
</data>
|
||||
<data name="UsingWorkingDirectory" xml:space="preserve">
|
||||
<value>Using working directory '{workingDirectory}'.</value>
|
||||
</data>
|
||||
<data name="ToolsDirectoryDescription" xml:space="preserve">
|
||||
<value>Location from which inside man was copied (in the .NET Framework case) or loaded.</value>
|
||||
</data>
|
||||
<data name="UriDescription" xml:space="preserve">
|
||||
<value>The URI to download the document from.</value>
|
||||
</data>
|
||||
<data name="MethodDescription" xml:space="preserve">
|
||||
<value>The name of the method to invoke on the '--service' instance. Default value '{defaultMethod}'.</value>
|
||||
</data>
|
||||
<data name="ServiceDescription" xml:space="preserve">
|
||||
<value>The qualified name of the service type to retrieve from dependency injection. Default value '{defaultService}'.</value>
|
||||
</data>
|
||||
<data name="MissingOptions" xml:space="preserve">
|
||||
<value>Missing required option '--{option1}' or '--{option2}'.</value>
|
||||
</data>
|
||||
<data name="DocumentDescription" xml:space="preserve">
|
||||
<value>The name of the document to pass to the '--method' method. Default value '{defaultDocumentName}'.</value>
|
||||
</data>
|
||||
<data name="UsingDocument" xml:space="preserve">
|
||||
<value>Using document name '{documentName}'.</value>
|
||||
</data>
|
||||
<data name="UsingMethod" xml:space="preserve">
|
||||
<value>Using method '{method}'.</value>
|
||||
</data>
|
||||
<data name="UsingService" xml:space="preserve">
|
||||
<value>Using service '{service}'.</value>
|
||||
</data>
|
||||
<data name="UsingUri" xml:space="preserve">
|
||||
<value>Using URI '{uri}'.</value>
|
||||
</data>
|
||||
<data name="MethodInvocationFailed" xml:space="preserve">
|
||||
<value>Method '{method}' of service '{service}' failed to generate document '{documentName}'.</value>
|
||||
</data>
|
||||
<data name="MissingEntryPoint" xml:space="preserve">
|
||||
<value>Assembly '{assemblyPath}' does not contain an entry point.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// 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.Linq;
|
||||
using static GetDocument.AnsiConstants;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal static class Reporter
|
||||
{
|
||||
public static bool IsVerbose { get; set; }
|
||||
public static bool NoColor { get; set; }
|
||||
public static bool PrefixOutput { get; set; }
|
||||
|
||||
public static string Colorize(string value, Func<string, string> colorizeFunc)
|
||||
=> NoColor ? value : colorizeFunc(value);
|
||||
|
||||
public static void WriteError(string message)
|
||||
=> WriteLine(Prefix("error: ", Colorize(message, x => Bold + Red + x + Reset)));
|
||||
|
||||
public static void WriteWarning(string message)
|
||||
=> WriteLine(Prefix("warn: ", Colorize(message, x => Bold + Yellow + x + Reset)));
|
||||
|
||||
public static void WriteInformation(string message)
|
||||
=> WriteLine(Prefix("info: ", message));
|
||||
|
||||
public static void WriteData(string message)
|
||||
=> WriteLine(Prefix("data: ", Colorize(message, x => Bold + Gray + x + Reset)));
|
||||
|
||||
public static void WriteVerbose(string message)
|
||||
{
|
||||
if (IsVerbose)
|
||||
{
|
||||
WriteLine(Prefix("verbose: ", Colorize(message, x => Bold + Black + x + Reset)));
|
||||
}
|
||||
}
|
||||
|
||||
private static string Prefix(string prefix, string value)
|
||||
=> PrefixOutput
|
||||
? string.Join(
|
||||
Environment.NewLine,
|
||||
value.Split(new[] { Environment.NewLine }, StringSplitOptions.None).Select(l => prefix + l))
|
||||
: value;
|
||||
|
||||
private static void WriteLine(string value)
|
||||
{
|
||||
if (NoColor)
|
||||
{
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnsiConsole.WriteLine(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// 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 GetDocument
|
||||
{
|
||||
internal class WrappedException : Exception
|
||||
{
|
||||
private readonly string _stackTrace;
|
||||
|
||||
public WrappedException(string type, string message, string stackTrace)
|
||||
: base(message)
|
||||
{
|
||||
Type = type;
|
||||
_stackTrace = stackTrace;
|
||||
}
|
||||
|
||||
public string Type { get; }
|
||||
|
||||
public override string ToString()
|
||||
=> _stackTrace;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
// 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.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
using Utilities = Microsoft.Build.Utilities;
|
||||
|
||||
namespace GenerationTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Downloads a file.
|
||||
/// </summary>
|
||||
public class DownloadFile : Utilities.Task, ICancelableTask
|
||||
{
|
||||
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
||||
|
||||
/// <summary>
|
||||
/// The URI to download.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Uri { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Destination for the downloaded file. If the file already exists, it is not re-downloaded unless
|
||||
/// <see cref="Overwrite"/> is true.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string DestinationPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should <see cref="DestinationPath"/> be overwritten. When <c>true</c>, the file is downloaded and its hash
|
||||
/// compared to the existing file. If those hashes do not match (or <see cref="DestinationPath"/> does not
|
||||
/// exist), <see cref="DestinationPath"/> is overwritten.
|
||||
/// </summary>
|
||||
public bool Overwrite { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of time in seconds to allow for downloading the file. Defaults to 2 minutes.
|
||||
/// </summary>
|
||||
public int TimeoutSeconds { get; set; } = 60 * 2;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Cancel() => _cts.Cancel();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Execute() => ExecuteAsync().Result;
|
||||
|
||||
public async Task<bool> ExecuteAsync()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Uri))
|
||||
{
|
||||
Log.LogError("Uri parameter must not be null or empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(Uri))
|
||||
{
|
||||
Log.LogError("DestinationPath parameter must not be null or empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var builder = new UriBuilder(Uri);
|
||||
if (!string.Equals(System.Uri.UriSchemeHttp, builder.Scheme, StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(System.Uri.UriSchemeHttps, builder.Scheme, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Log.LogError($"{nameof(Uri)} parameter does not have scheme {System.Uri.UriSchemeHttp} or " +
|
||||
$"{System.Uri.UriSchemeHttps}.");
|
||||
return false;
|
||||
}
|
||||
|
||||
await DownloadFileAsync(Uri, DestinationPath, Overwrite, _cts.Token, TimeoutSeconds, Log);
|
||||
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
|
||||
private static async Task DownloadFileAsync(
|
||||
string uri,
|
||||
string destinationPath,
|
||||
bool overwrite,
|
||||
CancellationToken cancellationToken,
|
||||
int timeoutSeconds,
|
||||
TaskLoggingHelper log)
|
||||
{
|
||||
var destinationExists = File.Exists(destinationPath);
|
||||
if (destinationExists && !overwrite)
|
||||
{
|
||||
log.LogMessage($"Not downloading '{uri}' to overwrite existing file '{destinationPath}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
log.LogMessage($"Downloading '{uri}' to '{destinationPath}'.");
|
||||
|
||||
using (var httpClient = new HttpClient
|
||||
{
|
||||
})
|
||||
{
|
||||
await DownloadFileCore.DownloadAsync(
|
||||
uri,
|
||||
destinationPath,
|
||||
httpClient,
|
||||
new LogWrapper(log),
|
||||
cancellationToken,
|
||||
timeoutSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GenerationTasks
|
||||
{
|
||||
internal static class DownloadFileCore
|
||||
{
|
||||
public static async Task DownloadAsync(
|
||||
string uri,
|
||||
string destinationPath,
|
||||
HttpClient httpClient,
|
||||
ILogWrapper log,
|
||||
CancellationToken cancellationToken,
|
||||
int timeoutSeconds)
|
||||
{
|
||||
// Timeout if the response has not begun within 1 minute
|
||||
httpClient.Timeout = TimeSpan.FromMinutes(1);
|
||||
|
||||
var destinationExists = File.Exists(destinationPath);
|
||||
var reachedCopy = false;
|
||||
try
|
||||
{
|
||||
using (var response = await httpClient.GetAsync(uri, cancellationToken))
|
||||
{
|
||||
response.EnsureSuccessStatusCode();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
using (var responseStreamTask = response.Content.ReadAsStreamAsync())
|
||||
{
|
||||
var finished = await Task.WhenAny(
|
||||
responseStreamTask,
|
||||
Task.Delay(TimeSpan.FromSeconds(timeoutSeconds)));
|
||||
|
||||
if (!ReferenceEquals(responseStreamTask, finished))
|
||||
{
|
||||
throw new TimeoutException($"Download failed to complete in {timeoutSeconds} seconds.");
|
||||
}
|
||||
|
||||
var responseStream = await responseStreamTask;
|
||||
if (destinationExists)
|
||||
{
|
||||
// Check hashes before using the downloaded information.
|
||||
var downloadHash = GetHash(responseStream);
|
||||
responseStream.Position = 0L;
|
||||
|
||||
byte[] destinationHash;
|
||||
using (var destinationStream = File.OpenRead(destinationPath))
|
||||
{
|
||||
destinationHash = GetHash(destinationStream);
|
||||
}
|
||||
|
||||
var sameHashes = downloadHash.LongLength == destinationHash.LongLength;
|
||||
for (var i = 0L; sameHashes && i < downloadHash.LongLength; i++)
|
||||
{
|
||||
sameHashes = downloadHash[i] == destinationHash[i];
|
||||
}
|
||||
|
||||
if (sameHashes)
|
||||
{
|
||||
log.LogInformational($"Not overwriting existing and matching file '{destinationPath}'.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// May need to create directory to hold the file.
|
||||
var destinationDirectory = Path.GetDirectoryName(destinationPath);
|
||||
if (!(string.IsNullOrEmpty(destinationDirectory) || Directory.Exists(destinationDirectory)))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
// Create or overwrite the destination file.
|
||||
reachedCopy = true;
|
||||
using (var outStream = File.Create(destinationPath))
|
||||
{
|
||||
responseStream.CopyTo(outStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex) when (destinationExists)
|
||||
{
|
||||
if (ex.InnerException is SocketException socketException)
|
||||
{
|
||||
log.LogWarning($"Unable to download {uri}, socket error code '{socketException.SocketErrorCode}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.LogWarning($"Unable to download {uri}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.LogError($"Downloading '{uri}' failed.");
|
||||
log.LogError(ex, showStackTrace: true);
|
||||
if (reachedCopy)
|
||||
{
|
||||
File.Delete(destinationPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GetHash(Stream stream)
|
||||
{
|
||||
using (var algorithm = SHA256.Create())
|
||||
{
|
||||
return algorithm.ComputeHash(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace GenerationTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds or corrects Namespace and OutputPath metadata in ServiceFileReference items.
|
||||
/// </summary>
|
||||
public class GetFileReferenceMetadata : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Default Namespace metadata value for C# output.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string CSharpNamespace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default directory for OutputPath values.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string OutputDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default Namespace metadata value for TypeScript output.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string TypeScriptNamespace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ServiceFileReference items to update.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] Inputs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The updated ServiceFileReference items. Will include Namespace and OutputPath metadata. OutputPath metadata
|
||||
/// will contain full paths.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] Outputs{ get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Execute()
|
||||
{
|
||||
var outputs = new List<ITaskItem>(Inputs.Length);
|
||||
foreach (var item in Inputs)
|
||||
{
|
||||
var newItem = new TaskItem(item);
|
||||
outputs.Add(newItem);
|
||||
|
||||
var codeGenerator = item.GetMetadata("CodeGenerator");
|
||||
var isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var @namespace = item.GetMetadata("Namespace");
|
||||
if (string.IsNullOrEmpty(@namespace))
|
||||
{
|
||||
@namespace = isTypeScript ? CSharpNamespace : TypeScriptNamespace;
|
||||
newItem.SetMetadata("Namespace", @namespace);
|
||||
}
|
||||
|
||||
var outputPath = item.GetMetadata("OutputPath");
|
||||
if (string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
var className = item.GetMetadata("ClassName");
|
||||
outputPath = className + (isTypeScript ? ".ts" : ".cs");
|
||||
}
|
||||
|
||||
outputPath = GetFullPath(outputPath);
|
||||
newItem.SetMetadata("OutputPath", outputPath);
|
||||
}
|
||||
|
||||
Outputs = outputs.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetFullPath(string path)
|
||||
{
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(OutputDirectory))
|
||||
{
|
||||
path = Path.Combine(OutputDirectory, path);
|
||||
}
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace GenerationTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds or corrects DocumentPath and project-related metadata in ServiceProjectReference items.
|
||||
/// </summary>
|
||||
public class GetProjectReferenceMetadata : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Default directory for DocumentPath values.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string DocumentDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ServiceFileReference items to update.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] Inputs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The updated ServiceFileReference items. Will include Namespace and OutputPath metadata. OutputPath metadata
|
||||
/// will contain full paths.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] Outputs{ get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Execute()
|
||||
{
|
||||
var outputs = new List<ITaskItem>(Inputs.Length);
|
||||
foreach (var item in Inputs)
|
||||
{
|
||||
var newItem = new TaskItem(item);
|
||||
outputs.Add(newItem);
|
||||
|
||||
var codeGenerator = item.GetMetadata("CodeGenerator");
|
||||
var isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var outputPath = item.GetMetadata("OutputPath");
|
||||
if (string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
var className = item.GetMetadata("ClassName");
|
||||
outputPath = className + (isTypeScript ? ".ts" : ".cs");
|
||||
}
|
||||
|
||||
outputPath = GetFullPath(outputPath);
|
||||
newItem.SetMetadata("OutputPath", outputPath);
|
||||
}
|
||||
|
||||
Outputs = outputs.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetFullPath(string path)
|
||||
{
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(DocumentDirectory))
|
||||
{
|
||||
path = Path.Combine(DocumentDirectory, path);
|
||||
}
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace GenerationTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds or corrects DocumentPath metadata in ServiceUriReference items.
|
||||
/// </summary>
|
||||
public class GetUriReferenceMetadata : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Default directory for DocumentPath metadata values.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string DocumentDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ServiceUriReference items to update.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] Inputs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The updated ServiceUriReference items. Will include DocumentPath metadata with full paths.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] Outputs{ get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Execute()
|
||||
{
|
||||
var outputs = new List<ITaskItem>(Inputs.Length);
|
||||
foreach (var item in Inputs)
|
||||
{
|
||||
var newItem = new TaskItem(item);
|
||||
outputs.Add(newItem);
|
||||
|
||||
var documentPath = item.GetMetadata("DocumentPath");
|
||||
if (string.IsNullOrEmpty(documentPath))
|
||||
{
|
||||
var uri = item.ItemSpec;
|
||||
var builder = new UriBuilder(uri);
|
||||
if (!builder.Uri.IsAbsoluteUri)
|
||||
{
|
||||
Log.LogError($"{nameof(Inputs)} item '{uri}' is not an absolute URI.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(Uri.UriSchemeHttp, builder.Scheme, StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(Uri.UriSchemeHttps, builder.Scheme, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Log.LogError($"{nameof(Inputs)} item '{uri}' does not have scheme {Uri.UriSchemeHttp} or " +
|
||||
$"{Uri.UriSchemeHttps}.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var host = builder.Host
|
||||
.Replace("/", string.Empty)
|
||||
.Replace("[", string.Empty)
|
||||
.Replace("]", string.Empty)
|
||||
.Replace(':', '_');
|
||||
var path = builder.Path
|
||||
.Replace("!", string.Empty)
|
||||
.Replace("'", string.Empty)
|
||||
.Replace("$", string.Empty)
|
||||
.Replace("%", string.Empty)
|
||||
.Replace("&", string.Empty)
|
||||
.Replace("(", string.Empty)
|
||||
.Replace(")", string.Empty)
|
||||
.Replace("*", string.Empty)
|
||||
.Replace("@", string.Empty)
|
||||
.Replace("~", string.Empty)
|
||||
.Replace('/', '_')
|
||||
.Replace(':', '_')
|
||||
.Replace(';', '_')
|
||||
.Replace('+', '_')
|
||||
.Replace('=', '_');
|
||||
|
||||
documentPath = host + path;
|
||||
if (char.IsLower(documentPath[0]))
|
||||
{
|
||||
documentPath = char.ToUpper(documentPath[0]) + documentPath.Substring(startIndex: 1);
|
||||
}
|
||||
|
||||
if (!documentPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
documentPath = $"{documentPath}.json";
|
||||
}
|
||||
}
|
||||
|
||||
documentPath = GetFullPath(documentPath);
|
||||
newItem.SetMetadata("DocumentPath", documentPath);
|
||||
}
|
||||
|
||||
Outputs = outputs.ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string GetFullPath(string path)
|
||||
{
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(DocumentDirectory))
|
||||
{
|
||||
path = Path.Combine(DocumentDirectory, path);
|
||||
}
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
|
||||
namespace GenerationTasks
|
||||
{
|
||||
internal interface ILogWrapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Logs specified informational <paramref name="message"/>. Implementations should be thread safe.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to log.</param>
|
||||
/// <param name="messageArgs">Optional arguments for formatting the <paramref name="message"/> string.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown when <paramref name="message"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
void LogInformational(string message, params object[] messageArgs);
|
||||
|
||||
/// <summary>
|
||||
/// Logs a warning with the specified <paramref name="message"/>. Implementations should be thread safe.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to log.</param>
|
||||
/// <param name="messageArgs">Optional arguments for formatting the <paramref name="message"/> string.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown when <paramref name="message"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
void LogWarning(string message, params object[] messageArgs);
|
||||
|
||||
/// <summary>
|
||||
/// Logs an error with the specified <paramref name="message"/>. Implementations should be thread safe.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to log.</param>
|
||||
/// <param name="messageArgs">Optional arguments for formatting the <paramref name="message"/> string.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown when <paramref name="message"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
void LogError(string message, params object[] messageArgs);
|
||||
|
||||
/// <summary>
|
||||
/// Logs an error with the message and (optionally) the stack trace of the given <paramref name="exception"/>.
|
||||
/// Implementations should be thread safe.
|
||||
/// </summary>
|
||||
/// <param name="exception">The <see cref="Exception"/> to log.</param>
|
||||
/// <param name="showStackTrace">
|
||||
/// If <see langword="true"/>, append stack trace to <paramref name="exception"/>'s message.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown when <paramref name="exception"/> is <see langword="null"/>.
|
||||
/// </exception>
|
||||
void LogError(Exception exception, bool showStackTrace);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace GenerationTasks
|
||||
{
|
||||
internal class LogWrapper : ILogWrapper
|
||||
{
|
||||
private readonly TaskLoggingHelper _log;
|
||||
|
||||
public LogWrapper(TaskLoggingHelper log)
|
||||
{
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public void LogError(string message, params object[] messageArgs)
|
||||
{
|
||||
_log.LogError(message, messageArgs);
|
||||
}
|
||||
|
||||
public void LogError(Exception exception, bool showStackTrace)
|
||||
{
|
||||
_log.LogErrorFromException(exception, showStackTrace);
|
||||
}
|
||||
|
||||
public void LogInformational(string message, params object[] messageArgs)
|
||||
{
|
||||
_log.LogMessage(message, messageArgs);
|
||||
}
|
||||
|
||||
public void LogWarning(string message, params object[] messageArgs)
|
||||
{
|
||||
_log.LogWarning(message, messageArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<!-- Execute PopulateNuspec fairly late. -->
|
||||
<GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);PopulateNuspec</GenerateNuspecDependsOn>
|
||||
|
||||
<!-- Do not complain about lack of lib folder. -->
|
||||
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||
|
||||
<Description>MSBuild tasks and targets for code generation</Description>
|
||||
<EnableApiCheck>false</EnableApiCheck>
|
||||
<IsPackable>false</IsPackable>
|
||||
<NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
|
||||
<PackageTags>Build Tasks;msbuild;DownloadFile;GetFilenameFromUri;code generation</PackageTags>
|
||||
<RootNamespace>GenerationTasks</RootNamespace>
|
||||
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ServiceProjectReferenceMetadata.targets" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="$(MicrosoftBuildUtilitiesCorePackageVersion)" />
|
||||
<PackageReference Condition="'$(TargetFramework)' == 'net461'" Include="System.Net.Http" Version="$(SystemNetHttpPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PopulateNuspec">
|
||||
<PropertyGroup>
|
||||
<NuspecProperties>
|
||||
id=$(PackageId);
|
||||
authors=$(Authors);
|
||||
configuration=$(Configuration);
|
||||
copyright=$(Copyright);
|
||||
description=$(PackageDescription);
|
||||
iconUrl=$(PackageIconUrl);
|
||||
licenseUrl=$(PackageLicenseUrl);
|
||||
owners=$(Company);
|
||||
projectUrl=$(PackageProjectUrl);
|
||||
repositoryCommit=$(RepositoryCommit);
|
||||
repositoryUrl=$(RepositoryUrl);
|
||||
tags=$(PackageTags.Replace(';', ' '));
|
||||
version=$(PackageVersion);
|
||||
</NuspecProperties>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<authors>$authors$</authors>
|
||||
<copyright>$copyright$</copyright>
|
||||
<description>$description$</description>
|
||||
<developmentDependency>true</developmentDependency>
|
||||
<iconUrl>$iconUrl$</iconUrl>
|
||||
<licenseUrl>$licenseUrl$</licenseUrl>
|
||||
<minClientVersion>2.8</minClientVersion>
|
||||
<owners>$owners$</owners>
|
||||
<projectUrl>$projectUrl$</projectUrl>
|
||||
<repository type="git" url="$repositoryUrl$" commit="$repositoryCommit$" />
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<tags>$tags$</tags>
|
||||
<version>$version$</version>
|
||||
<dependencies>
|
||||
<dependency id="NSwag.MSBuild" version="11.18.6" include="runtime,build,native,contentfiles,analyzers" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<file src="bin\$configuration$\**" target="tasks" exclude="**\Microsoft.Build.*.dll" />
|
||||
<file src="build\*.*" target="build" />
|
||||
<file src="buildMultiTargeting\*.*" target="buildMultiTargeting" />
|
||||
</files>
|
||||
</package>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!-- Collect properties only in inner build. Execute unconditionally before WriteServiceProjectReferenceMetadata. -->
|
||||
<Target Name="GetServiceProjectReferenceMetadata"
|
||||
BeforeTargets="WriteServiceProjectReferenceMetadataCore"
|
||||
Condition="'$(TargetFramework)' != ''"
|
||||
Returns="@(ServiceProjectReferenceMetadata)">
|
||||
<ItemGroup Condition="'$(TargetFramework)' != ''">
|
||||
<ServiceProjectReferenceMetadata Include="DefaultDocumentName: $(DefaultServiceProjectDocumentName)" />
|
||||
<ServiceProjectReferenceMetadata Include="DefaultMethod: $(DefaultServiceProjectMethod)" />
|
||||
<ServiceProjectReferenceMetadata Include="DefaultService: $(DefaultServiceProjectService)" />
|
||||
<ServiceProjectReferenceMetadata Include="DefaultUri: $(DefaultServiceProjectUri)" />
|
||||
|
||||
<ServiceProjectReferenceMetadata Include="AssemblyPath: $(TargetPath)" />
|
||||
<ServiceProjectReferenceMetadata Include="Configuration: $(Configuration)" />
|
||||
<ServiceProjectReferenceMetadata Include="ExtensionsPath: $(MSBuildProjectExtensionsPath)" />
|
||||
<ServiceProjectReferenceMetadata Include="RuntimeIdentifier: $(RuntimeIdentifier)" />
|
||||
<ServiceProjectReferenceMetadata Include="TargetFramework: $(TargetFramework)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="WriteServiceProjectReferenceMetadata" Returns="@(ServiceProjectReferenceMetadata)">
|
||||
<MSBuild Condition="'$(TargetFramework)' == ''"
|
||||
Projects="$(MSBuildProjectFile)"
|
||||
Targets="WriteServiceProjectReferenceMetadata"
|
||||
Properties="TargetFramework=$(TargetFrameworks.Split(';')[0]);ServiceProjectReferenceMetadataFile=$(ServiceProjectReferenceMetadataFile)" />
|
||||
|
||||
<WriteLinesToFile Condition="'$(TargetFramework)' != ''"
|
||||
File="$(ServiceProjectReferenceMetadataPath)"
|
||||
Lines="@(ServiceProjectReferenceMetadata)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project>
|
||||
<Import Project="NSwagServiceReference.props" />
|
||||
<PropertyGroup>
|
||||
<_GenerationTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0</_GenerationTasksAssemblyTarget>
|
||||
<_GenerationTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' != 'Core'">net461</_GenerationTasksAssemblyTarget>
|
||||
<_GenerationTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_GenerationTasksAssemblyTarget)/GenerationTasks.dll</_GenerationTasksAssemblyPath>
|
||||
<_GenerationTasksAssemblyTarget />
|
||||
</PropertyGroup>
|
||||
<UsingTask TaskName="GenerationTasks.GetFileReferenceMetadata" AssemblyFile="$(_GenerationTasksAssemblyPath)" />
|
||||
<UsingTask TaskName="GenerationTasks.GetProjectReferenceMetadata" AssemblyFile="$(_GenerationTasksAssemblyPath)" />
|
||||
<UsingTask TaskName="GenerationTasks.GetUriReferenceMetadata" AssemblyFile="$(_GenerationTasksAssemblyPath)" />
|
||||
<UsingTask TaskName="GenerationTasks.DownloadFile" AssemblyFile="$(_GenerationTasksAssemblyPath)" />
|
||||
|
||||
<PropertyGroup>
|
||||
<ServiceProjectReferenceCheckIfNewer Condition="'$(ServiceProjectReferenceCheckIfNewer)' == ''">true</ServiceProjectReferenceCheckIfNewer>
|
||||
<ServiceProjectReferenceDirectory
|
||||
Condition="'$(ServiceProjectReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceProjectReferenceDirectory)'))</ServiceProjectReferenceDirectory>
|
||||
|
||||
<ServiceUriReferenceCheckIfNewer Condition="'$(ServiceUriReferenceCheckIfNewer)' == ''">true</ServiceUriReferenceCheckIfNewer>
|
||||
<ServiceUriReferenceDirectory
|
||||
Condition="'$(ServiceUriReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceUriReferenceDirectory)'))</ServiceUriReferenceDirectory>
|
||||
|
||||
<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>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
Well-known metadata of the code and document generator item groups. ServiceProjectReference and ServiceUriReference
|
||||
items may also include ServiceFileReference metadata.
|
||||
-->
|
||||
<ItemDefinitionGroup>
|
||||
<ServiceProjectReference>
|
||||
<!-- Name of the API description document generator. -->
|
||||
<DocumentGenerator>Default</DocumentGenerator>
|
||||
<!--
|
||||
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".
|
||||
-->
|
||||
<DocumentName />
|
||||
<!--
|
||||
Full path where the API description document is placed. Default filename is %(Filename).%(DocumentName).json.
|
||||
Filenames and relative paths (if explicitly set) are combined with $(ServiceProjectReferenceDirectory).
|
||||
-->
|
||||
<DocumentPath />
|
||||
<!--
|
||||
Method Default document generator should invoke on the %(Service) to generate document.
|
||||
Default is set in server project, falling back to "Generate".
|
||||
-->
|
||||
<Method />
|
||||
<!--
|
||||
Service Default document generator should retrieve from DI to generate document.
|
||||
Default is set in server project, falling back to "Microsoft.Extensions.ApiDescription.IDocumentProvider".
|
||||
-->
|
||||
<Service />
|
||||
<!--
|
||||
URI from which Default document generator should download the document. Used only if invoking the %(Method) on
|
||||
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).
|
||||
-->
|
||||
<DocumentPath />
|
||||
</ServiceUriReference>
|
||||
|
||||
<ServiceFileReference>
|
||||
<!-- Name of the class to generate. -->
|
||||
<ClassName>%(Filename)Client</ClassName>
|
||||
<!-- Code generator to use. Required. -->
|
||||
<CodeGenerator />
|
||||
<!--
|
||||
Namespace to contain generated class. Default is either $(ServiceFileReferenceCSharpNamespace) or
|
||||
$(ServiceFileReferenceTypeScriptNamespace), depending on target language.
|
||||
-->
|
||||
<Namespace />
|
||||
<!--
|
||||
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).
|
||||
-->
|
||||
<OutputPath />
|
||||
</ServiceFileReference>
|
||||
</ItemDefinitionGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project>
|
||||
<Import Project="NSwagServiceReference.targets" />
|
||||
<Target Name="_CheckServiceReferences">
|
||||
<Error Condition="'@(ServiceProjectReference)' != '' AND '%(ServiceProjectReference.CodeGenerator)' == ''"
|
||||
Text="ServiceProjectReference items '@(ServiceProjectReference)' lack CodeGenerator metadata." />
|
||||
<Error Condition="'@(ServiceUriReference)' != '' AND '%(ServiceUriReference.CodeGenerator)' == ''"
|
||||
Text="ServiceUriReference items '@(ServiceUriReference)' lack CodeGenerator metadata." />
|
||||
<Error Condition="'@(ServiceFileReference)' != '' AND '%(ServiceFileReference.CodeGenerator)' == ''"
|
||||
Text="ServiceFileReference items '@(ServiceFileReference)' lack CodeGenerator metadata." />
|
||||
</Target>
|
||||
|
||||
<!-- ServiceProjectReference support -->
|
||||
|
||||
<!-- Metadata setup phase 1: Ensure items have TargetFramework metadata. Call GetTargetFrameworks in the target project. -->
|
||||
<!-- Inputs and outputs cause MSBuild to run target unconditionally and to batch it (run once per project). -->
|
||||
<Target Name="_ServiceProjectReferenceGenerator_GetTargetFramework"
|
||||
Inputs="%(ServiceProjectReference.FullPath)"
|
||||
Outputs="<not-a-file !>">
|
||||
<PropertyGroup>
|
||||
<_FullPath>%(ServiceProjectReference.FullPath)</_FullPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MSBuild Projects="$(_FullPath)"
|
||||
RebaseOutputs="true"
|
||||
RemoveProperties="TargetFramework;TargetFrameworks;RuntimeIdentifier"
|
||||
Targets="GetTargetFrameworks"
|
||||
UseResultsCache="true">
|
||||
<Output TaskParameter="TargetOutputs" ItemName="_Temporary" />
|
||||
</MSBuild>
|
||||
|
||||
<!-- Please excuse the mess necessary to extract information from _Temporary and use it in ServiceProjectReference. -->
|
||||
<PropertyGroup>
|
||||
<_TargetFrameworks>%(_Temporary.TargetFrameworks)</_TargetFrameworks>
|
||||
<_TargetFramework>$(_TargetFrameworks.Split(';')[0])</_TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ServiceProjectReference Update="@(ServiceProjectReference)" Condition="'%(FullPath)' == '$(_FullPath)'">
|
||||
<TargetFramework Condition="'%(ServiceProjectReference.TargetFramework)' == ''">$(_TargetFramework)</TargetFramework>
|
||||
</ServiceProjectReference>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<_FullPath />
|
||||
<_TargetFramework />
|
||||
<_TargetFrameworks />
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<!-- 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="<not-a-file !>">
|
||||
<PropertyGroup>
|
||||
<_FullPath>%(ServiceProjectReference.FullPath)</_FullPath>
|
||||
<_TargetFramework>%(ServiceProjectReference.TargetFramework)</_TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
|
||||
<Message Importance="high" Text="%0A_ServiceProjectReferenceGenerator_GetProjectTargetPath: '$(_FullPath)' '$(_TargetFramework)'" />
|
||||
<MSBuild Projects="$(_FullPath)"
|
||||
Properties="TargetFramework=$(_TargetFramework)"
|
||||
RebaseOutputs="true"
|
||||
RemoveProperties="TargetFrameworks;RuntimeIdentifier"
|
||||
Targets="GetTargetPath"
|
||||
UseResultsCache="true">
|
||||
<Output TaskParameter="TargetOutputs" ItemName="_Temporary" />
|
||||
</MSBuild>
|
||||
|
||||
<PropertyGroup>
|
||||
<_ProjectTargetPath>%(_Temporary.FullPath)</_ProjectTargetPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ServiceProjectReference Update="@(ServiceProjectReference)"
|
||||
Condition="'%(FullPath)' == '$(_FullPath)' AND '%(ServiceProjectReference.TargetFramework)' == '$(_TargetFramework)'">
|
||||
<ProjectTargetPath>$(_ProjectTargetPath)</ProjectTargetPath>
|
||||
</ServiceProjectReference>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<_FullPath />
|
||||
<_ProjectTargetPath />
|
||||
<_TargetFramework />
|
||||
</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)"
|
||||
BuildInParallel="$(BuildInParallel)"
|
||||
RemoveProperties="TargetFrameworks;RuntimeIdentifier"
|
||||
Targets="Build" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_ServiceProjectReferenceGenerator_Core"
|
||||
Condition="'@(ServiceProjectReference)' != ''"
|
||||
DependsOnTargets="@(ServiceProjectReference -> '%(DocumentGenerator)DocumentGenerator')" />
|
||||
|
||||
<Target Name="ServiceProjectReferenceGenerator"
|
||||
Condition="'@(ServiceProjectReference)' != ''"
|
||||
DependsOnTargets="$(ServiceProjectReferenceGeneratorDependsOn)" />
|
||||
|
||||
<!-- DefaultDocumentGenerator -->
|
||||
|
||||
<Target Name="_DefaultDocumentGenerator_GetMetadata">
|
||||
<ItemGroup>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
<_Temporary Include="@(ServiceProjectReference -> WithMetadataValue('DocumentGenerator', 'Default'))" />
|
||||
</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." />
|
||||
</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">
|
||||
<ItemGroup>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
|
||||
<GenerationTasks.GetUriReferenceMetadata DocumentDirectory="$(ServiceUriReferenceDirectory)" Inputs="@(ServiceUriReference)">
|
||||
<Output TaskParameter="Outputs" ItemName="_Temporary" />
|
||||
</GenerationTasks.GetUriReferenceMetadata>
|
||||
|
||||
<ItemGroup>
|
||||
<ServiceUriReference Remove="@(ServiceUriReference)" />
|
||||
<ServiceUriReference Include="@(_Temporary)" />
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_ServiceUriReferenceGenerator_Core" Condition="'@(ServiceUriReference)' != ''">
|
||||
<GenerationTasks.DownloadFile Uri="%(ServiceUriReference.Identity)"
|
||||
DestinationPath="%(DocumentPath)"
|
||||
Overwrite="$(ServiceUriReferenceCheckIfNewer)" />
|
||||
|
||||
<ItemGroup>
|
||||
<ServiceFileReference Remove="@(ServiceUriReference -> '%(DocumentPath)')" />
|
||||
<ServiceFileReference Include="@(ServiceUriReference -> '%(DocumentPath)')" SourceUri="%(ServiceUriReference.Identity)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="ServiceUriReferenceGenerator" DependsOnTargets="$(ServiceUriReferenceGeneratorDependsOn)" />
|
||||
|
||||
<!-- ServiceFileReference support -->
|
||||
|
||||
<Target Name="_ServiceFileReferenceGenerator_GetMetadata">
|
||||
<ItemGroup>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
|
||||
<GenerationTasks.GetFileReferenceMetadata DocumentDirectory="$(ServiceFileReferenceDirectory)" Inputs="@(ServiceFileReference)">
|
||||
<Output TaskParameter="Outputs" ItemName="_Temporary" />
|
||||
</GenerationTasks.GetFileReferenceMetadata>
|
||||
|
||||
<ItemGroup>
|
||||
<ServiceFileReference Remove="@(ServiceFileReference)" />
|
||||
<ServiceFileReference Include="@(_Temporary)" />
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_ServiceFileReferenceGenerator_Core"
|
||||
Condition="'@(ServiceFileReference)' != ''"
|
||||
DependsOnTargets="@(ServiceFileReference -> '%(CodeGenerator)CodeGenerator')" />
|
||||
|
||||
<Target Name="ServiceFileReferenceGenerator" BeforeTargets="BeforeCompile" DependsOnTargets="$(ServiceFileReferenceGeneratorDependsOn)" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<NSwagDocumentGeneratorDependsOn>
|
||||
_NSwagDocumentGenerator_GetMetadata;
|
||||
_NSwagDocumentGenerator_Core;
|
||||
_NSwagDocumentGenerator_SetMetadata
|
||||
</NSwagDocumentGeneratorDependsOn>
|
||||
<NSwagCSharpCodeGeneratorDependsOn>
|
||||
_NSwagCSharpCodeGenerator_GetMetadata;
|
||||
_NSwagCSharpCodeGenerator_Core;
|
||||
_NSwagCSharpCodeGenerator_SetMetadata
|
||||
</NSwagCSharpCodeGeneratorDependsOn>
|
||||
<NSwagTypeScriptCodeGeneratorDependsOn>
|
||||
_NSwagTypeScriptCodeGenerator_GetMetadata;
|
||||
_NSwagTypeScriptCodeGenerator_Core;
|
||||
_NSwagTypeScriptCodeGenerator_SetMetadata
|
||||
</NSwagTypeScriptCodeGeneratorDependsOn>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<Project>
|
||||
<!-- ServiceProjectReference support -->
|
||||
|
||||
<Target Name="_NSwagDocumentGenerator_GetMetadata">
|
||||
<ItemGroup>
|
||||
<_NSwagTemporary Remove="@(_NSwagTemporary)" />
|
||||
<_NSwagTemporary Include="@(ServiceProjectReference -> WithMetadataValue('DocumentGenerator', 'NSwag'))">
|
||||
<Options
|
||||
Condition="'%(ServiceFileReference.Options)' == '' AND '$(NSwagDocumentGeneratorDefaultOptions)' != ''">$(NSwagDocumentGeneratorDefaultOptions)</Options>
|
||||
</_NSwagTemporary>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_NSwagDocumentGenerator_Core" Inputs="%(_NSwagTemporary.ProjectTargetPath)" Outputs="%(_NSwagTemporary.DocumentPath)">
|
||||
<!-- aspnetcore2swagger -->
|
||||
<PropertyGroup>
|
||||
<_Command>$(NSwagExe_Core21) aspnetcore2swagger /Configuration:$(Configuration) /NoBuild:true</_Command>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Importance="high" Text="%0A$(_Command) /Project:%(FullPath) /output:%(DocumentPath) /TargetFramework:%(TargetFramework) %(_NSwagTemporary.Options)" />
|
||||
<Exec IgnoreExitCode="$([System.IO.File]::Exists('%(DocumentPath)'))"
|
||||
Command="$(_Command) /Project:%(FullPath) /output:%(DocumentPath) /TargetFramework:%(TargetFramework) %(_NSwagTemporary.Options)" />
|
||||
|
||||
<PropertyGroup>
|
||||
<_Command />
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
Separate from _NSwagDocumentGenerator_Core to ensure ServiceFileReference items are complete even if
|
||||
ServiceProjectReference items are not built in any batch.
|
||||
-->
|
||||
<Target Name="_NSwagDocumentGenerator_SetMetadata" Condition="'@(_NSwagTemporary)' != ''">
|
||||
<ItemGroup>
|
||||
<ServiceFileReference Remove="@(_NSwagTemporary -> '%(DocumentPath)')" />
|
||||
<ServiceFileReference Include="@(_NSwagTemporary -> '%(DocumentPath)')" SourceProject="%(_NSwagTemporary.FullPath)" />
|
||||
<_NSwagTemporary Remove="@(_NSwagTemporary)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="NSwagDocumentGenerator" DependsOnTargets="$(NSwagDocumentGeneratorDependsOn)" />
|
||||
|
||||
<!-- ServiceFileReference support for C# -->
|
||||
|
||||
<Target Name="_NSwagCSharpCodeGenerator_GetMetadata">
|
||||
<ItemGroup>
|
||||
<_NSwagTemporary Remove="@(_NSwagTemporary)" />
|
||||
<_NSwagTemporary Include="@(ServiceFileReference -> WithMetadataValue('CodeGenerator', 'NSwagCSharp'))">
|
||||
<Options
|
||||
Condition="'%(ServiceFileReference.Options)' == '' AND '$(NSwagCSharpCodeGeneratorDefaultOptions)' != ''">$(NSwagCSharpCodeGeneratorDefaultOptions)</Options>
|
||||
</_NSwagTemporary>
|
||||
<_NSwagTemporary Update="@(_NSwagTemporary)">
|
||||
<OutputPath Condition="'%(_NSwagTemporary.OutputPath)' == ''">$(ServiceFileReferenceDirectory)%(ClassName).cs</OutputPath>
|
||||
</_NSwagTemporary>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_NSwagCSharpCodeGenerator_Core" Inputs="%(_NSwagTemporary.FullPath)" Outputs="%(OutputPath)">
|
||||
<PropertyGroup>
|
||||
<_Command>$(NSwagExe_Core21) swagger2csclient /namespace:$(NSwagCSharpCodeGeneratorNamespace)</_Command>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Importance="high" Text="%0A$(_Command) /className:%(ClassName) /input:%(FullPath) /output:%(OutputPath) %(_NSwagTemporary.Options)" />
|
||||
<Exec IgnoreExitCode="$([System.IO.File]::Exists('%(OutputPath)'))"
|
||||
Command="$(_Command) /className:%(ClassName) /input:%(FullPath) /output:%(OutputPath) %(_NSwagTemporary.Options)" />
|
||||
|
||||
<PropertyGroup>
|
||||
<_Command />
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
Separate from _NSwagCSharpCodeGenerator_Core to ensure Compile items are complete even if ServiceFileReference
|
||||
items are both written outside the project and not included in a batch.
|
||||
-->
|
||||
<Target Name="_NSwagCSharpCodeGenerator_SetMetadata" Condition="'@(_NSwagTemporary)' != ''">
|
||||
<Message Importance="high" Text="%0A_NSwagCSharpCodeGenerator_SetMetadata: @(_NSwagTemporary -> '%(OutputPath)')" />
|
||||
<Message Importance="high" Text="_NSwagCSharpCodeGenerator_SetMetadata: '%(OutputPath)' '%(FullPath)' '%(_NSwagTemporary.SourceProject)' '%(_NSwagTemporary.SourceUrl)'" />
|
||||
<ItemGroup>
|
||||
<Compile Remove="@(_NSwagTemporary -> '%(OutputPath)')" />
|
||||
<Compile Include="@(_NSwagTemporary -> '%(OutputPath)')" />
|
||||
<_NSwagTemporary Remove="@(_NSwagTemporary)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="NSwagCSharpCodeGenerator" DependsOnTargets="$(NSwagCSharpCodeGeneratorDependsOn)" />
|
||||
|
||||
<!-- ServiceFileReference support for TypeScript -->
|
||||
|
||||
<Target Name="_NSwagTypeScriptCodeGenerator_GetMetadata">
|
||||
<ItemGroup>
|
||||
<_NSwagTemporary Remove="@(_NSwagTemporary)" />
|
||||
<_NSwagTemporary Include="@(ServiceFileReference -> WithMetadataValue('CodeGenerator', 'NSwagTypeScript'))">
|
||||
<Options
|
||||
Condition="'%(ServiceFileReference.Options)' == '' AND '$(NSwagTypeScriptCodeGeneratorDefaultOptions)' != ''">$(NSwagTypeScriptCodeGeneratorDefaultOptions)</Options>
|
||||
</_NSwagTemporary>
|
||||
<_NSwagTemporary Update="@(_NSwagTemporary)">
|
||||
<OutputPath Condition="'%(_NSwagTemporary.OutputPath)' == ''">$(ServiceFileReferenceDirectory)%(ClassName).ts</OutputPath>
|
||||
</_NSwagTemporary>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_NSwagTypeScriptCodeGenerator_Core" Inputs="%(_NSwagTemporary.FullPath)" Outputs="%(OutputPath)">
|
||||
<PropertyGroup>
|
||||
<_Command>$(NSwagExe_Core21) swagger2tsclient /namespace:$(NSwagTypeScriptCodeGeneratorNamespace)</_Command>
|
||||
</PropertyGroup>
|
||||
|
||||
<Message Importance="high" Text="%0A$(_Command) /className:%(ClassName) /input:%(FullPath) /output:%(OutputPath) %(_NSwagTemporary.Options)" />
|
||||
<Exec IgnoreExitCode="$([System.IO.File]::Exists('%(OutputPath)'))"
|
||||
Command="$(_Command) /className:%(ClassName) /input:%(FullPath) /output:%(OutputPath) %(_NSwagTemporary.Options)" />
|
||||
|
||||
<PropertyGroup>
|
||||
<_Command />
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
Separate from _NSwagTypeScriptCodeGenerator_Core to ensure Compile items are complete even if ServiceFileReference
|
||||
items are both written outside the project and not included in a batch.
|
||||
-->
|
||||
<Target Name="_NSwagTypeScriptCodeGenerator_SetMetadata" Condition="'@(_NSwagTemporary)' != ''">
|
||||
<ItemGroup>
|
||||
<TypeScriptCompile Remove="@(_NSwagTemporary -> '%(OutputPath)')" />
|
||||
<TypeScriptCompile Include="@(_NSwagTemporary -> '%(OutputPath)')" />
|
||||
<_NSwagTemporary Remove="@(_NSwagTemporary)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="NSwagTypeScriptCodeGenerator" DependsOnTargets="$(NSwagTypeScriptCodeGeneratorDependsOn)" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?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>
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using GetDocument.Properties;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace GetDocument.Commands
|
||||
{
|
||||
internal class InvokeCommand : HelpCommandBase
|
||||
{
|
||||
private const string InsideManName = "GetDocument.Insider";
|
||||
|
||||
private CommandOption _configuration;
|
||||
private CommandOption _framework;
|
||||
private CommandOption _msbuildprojectextensionspath;
|
||||
private CommandOption _output;
|
||||
private CommandOption _project;
|
||||
private CommandOption _runtime;
|
||||
private IList<string> _args;
|
||||
|
||||
public override void Configure(CommandLineApplication command)
|
||||
{
|
||||
var options = new ProjectOptions();
|
||||
options.Configure(command);
|
||||
|
||||
_project = options.Project;
|
||||
_framework = options.Framework;
|
||||
_configuration = options.Configuration;
|
||||
_runtime = options.Runtime;
|
||||
_msbuildprojectextensionspath = options.MSBuildProjectExtensionsPath;
|
||||
|
||||
_output = command.Option("--output <Path>", Resources.OutputDescription);
|
||||
command.VersionOption("--version", ProductInfo.GetVersion);
|
||||
_args = command.RemainingArguments;
|
||||
|
||||
base.Configure(command);
|
||||
}
|
||||
|
||||
protected override int Execute()
|
||||
{
|
||||
var projectFile = FindProjects(
|
||||
_project.Value(),
|
||||
Resources.NoProject,
|
||||
Resources.MultipleProjects);
|
||||
Reporter.WriteVerbose(Resources.UsingProject(projectFile));
|
||||
|
||||
var project = Project.FromFile(
|
||||
projectFile,
|
||||
_msbuildprojectextensionspath.Value(),
|
||||
_framework.Value(),
|
||||
_configuration.Value(),
|
||||
_runtime.Value());
|
||||
if (!File.Exists(project.AssemblyPath))
|
||||
{
|
||||
throw new CommandException(Resources.MustBuild);
|
||||
}
|
||||
|
||||
var thisPath = Path.GetFullPath(Path.GetDirectoryName(typeof(InvokeCommand).Assembly.Location));
|
||||
|
||||
string executable = null;
|
||||
var cleanupExecutable = false;
|
||||
try
|
||||
{
|
||||
string toolsDirectory;
|
||||
var args = new List<string>();
|
||||
var targetFramework = new FrameworkName(project.TargetFrameworkMoniker);
|
||||
switch (targetFramework.Identifier)
|
||||
{
|
||||
case ".NETFramework":
|
||||
cleanupExecutable = true;
|
||||
executable = Path.Combine(project.OutputPath, InsideManName + ".exe");
|
||||
toolsDirectory = Path.Combine(
|
||||
thisPath,
|
||||
project.PlatformTarget == "x86" ? "net461-x86" : "net461");
|
||||
|
||||
var executableSource = Path.Combine(toolsDirectory, InsideManName + ".exe");
|
||||
File.Copy(executableSource, executable, overwrite: true);
|
||||
|
||||
if (!string.IsNullOrEmpty(project.ConfigPath))
|
||||
{
|
||||
File.Copy(project.ConfigPath, executable + ".config", overwrite: true);
|
||||
}
|
||||
break;
|
||||
|
||||
case ".NETCoreApp":
|
||||
executable = "dotnet";
|
||||
toolsDirectory = Path.Combine(thisPath, "netcoreapp2.0");
|
||||
|
||||
if (targetFramework.Version < new Version(2, 0))
|
||||
{
|
||||
throw new CommandException(
|
||||
Resources.NETCoreApp1Project(project.Name, targetFramework.Version));
|
||||
}
|
||||
|
||||
args.Add("exec");
|
||||
args.Add("--depsFile");
|
||||
args.Add(project.DepsPath);
|
||||
|
||||
if (!string.IsNullOrEmpty(project.AssetsPath))
|
||||
{
|
||||
using (var reader = new JsonTextReader(File.OpenText(project.AssetsPath)))
|
||||
{
|
||||
var projectAssets = JToken.ReadFrom(reader);
|
||||
var packageFolders = projectAssets["packageFolders"]
|
||||
.Children<JProperty>()
|
||||
.Select(p => p.Name);
|
||||
|
||||
foreach (var packageFolder in packageFolders)
|
||||
{
|
||||
args.Add("--additionalProbingPath");
|
||||
args.Add(packageFolder.TrimEnd(Path.DirectorySeparatorChar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(project.RuntimeConfigPath))
|
||||
{
|
||||
args.Add("--runtimeConfig");
|
||||
args.Add(project.RuntimeConfigPath);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(project.RuntimeFrameworkVersion))
|
||||
{
|
||||
args.Add("--fx-version");
|
||||
args.Add(project.RuntimeFrameworkVersion);
|
||||
}
|
||||
|
||||
args.Add(Path.Combine(toolsDirectory, InsideManName + ".dll"));
|
||||
break;
|
||||
|
||||
case ".NETStandard":
|
||||
throw new CommandException(Resources.NETStandardProject(project.Name));
|
||||
|
||||
default:
|
||||
throw new CommandException(
|
||||
Resources.UnsupportedFramework(project.Name, targetFramework.Identifier));
|
||||
}
|
||||
|
||||
args.AddRange(_args);
|
||||
args.Add("--assembly");
|
||||
args.Add(project.AssemblyPath);
|
||||
args.Add("--tools-directory");
|
||||
args.Add(toolsDirectory);
|
||||
|
||||
if (!(args.Contains("--method") || string.IsNullOrEmpty(project.DefaultMethod)))
|
||||
{
|
||||
args.Add("--method");
|
||||
args.Add(project.DefaultMethod);
|
||||
}
|
||||
|
||||
if (!(args.Contains("--service") || string.IsNullOrEmpty(project.DefaultService)))
|
||||
{
|
||||
args.Add("--service");
|
||||
args.Add(project.DefaultService);
|
||||
}
|
||||
|
||||
if (!(args.Contains("--uri") || string.IsNullOrEmpty(project.DefaultUri)))
|
||||
{
|
||||
args.Add("--uri");
|
||||
args.Add(project.DefaultUri);
|
||||
}
|
||||
|
||||
if (_output.HasValue())
|
||||
{
|
||||
args.Add("--output");
|
||||
args.Add(Path.GetFullPath(_output.Value()));
|
||||
}
|
||||
|
||||
if (Reporter.IsVerbose)
|
||||
{
|
||||
args.Add("--verbose");
|
||||
}
|
||||
|
||||
if (Reporter.NoColor)
|
||||
{
|
||||
args.Add("--no-color");
|
||||
}
|
||||
|
||||
if (Reporter.PrefixOutput)
|
||||
{
|
||||
args.Add("--prefix-output");
|
||||
}
|
||||
|
||||
return Exe.Run(executable, args, project.Directory);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (cleanupExecutable && !string.IsNullOrEmpty(executable))
|
||||
{
|
||||
File.Delete(executable);
|
||||
File.Delete(executable + ".config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindProjects(
|
||||
string path,
|
||||
string errorWhenNoProject,
|
||||
string errorWhenMultipleProjects)
|
||||
{
|
||||
var specified = true;
|
||||
if (path == null)
|
||||
{
|
||||
specified = false;
|
||||
path = Directory.GetCurrentDirectory();
|
||||
}
|
||||
else if (!Directory.Exists(path)) // It's not a directory
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
var projectFiles = Directory
|
||||
.EnumerateFiles(path, "*.*proj", SearchOption.TopDirectoryOnly)
|
||||
.Where(f => !string.Equals(Path.GetExtension(f), ".xproj", StringComparison.OrdinalIgnoreCase))
|
||||
.Take(2)
|
||||
.ToList();
|
||||
if (projectFiles.Count == 0)
|
||||
{
|
||||
throw new CommandException(
|
||||
specified
|
||||
? Resources.NoProjectInDirectory(path)
|
||||
: errorWhenNoProject);
|
||||
}
|
||||
if (projectFiles.Count != 1)
|
||||
{
|
||||
throw new CommandException(
|
||||
specified
|
||||
? Resources.MultipleProjectsInDirectory(path)
|
||||
: errorWhenMultipleProjects);
|
||||
}
|
||||
|
||||
return projectFiles[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal static class Exe
|
||||
{
|
||||
public static int Run(
|
||||
string executable,
|
||||
IReadOnlyList<string> args,
|
||||
string workingDirectory = null,
|
||||
bool interceptOutput = false)
|
||||
{
|
||||
var arguments = ToArguments(args);
|
||||
|
||||
Reporter.WriteVerbose(executable + " " + arguments);
|
||||
|
||||
var startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = executable,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = interceptOutput
|
||||
};
|
||||
if (workingDirectory != null)
|
||||
{
|
||||
startInfo.WorkingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
var process = Process.Start(startInfo);
|
||||
|
||||
if (interceptOutput)
|
||||
{
|
||||
string line;
|
||||
while ((line = process.StandardOutput.ReadLine()) != null)
|
||||
{
|
||||
Reporter.WriteVerbose(line);
|
||||
}
|
||||
}
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
return process.ExitCode;
|
||||
}
|
||||
|
||||
private static string ToArguments(IReadOnlyList<string> args)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
for (var i = 0; i < args.Count; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
builder.Append(" ");
|
||||
}
|
||||
|
||||
if (args[i].IndexOf(' ') == -1)
|
||||
{
|
||||
builder.Append(args[i]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.Append("\"");
|
||||
|
||||
var pendingBackslashs = 0;
|
||||
for (var j = 0; j < args[i].Length; j++)
|
||||
{
|
||||
switch (args[i][j])
|
||||
{
|
||||
case '\"':
|
||||
if (pendingBackslashs != 0)
|
||||
{
|
||||
builder.Append('\\', pendingBackslashs * 2);
|
||||
pendingBackslashs = 0;
|
||||
}
|
||||
builder.Append("\\\"");
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
pendingBackslashs++;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (pendingBackslashs != 0)
|
||||
{
|
||||
if (pendingBackslashs == 1)
|
||||
{
|
||||
builder.Append("\\");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append('\\', pendingBackslashs * 2);
|
||||
}
|
||||
|
||||
pendingBackslashs = 0;
|
||||
}
|
||||
|
||||
builder.Append(args[i][j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingBackslashs != 0)
|
||||
{
|
||||
builder.Append('\\', pendingBackslashs * 2);
|
||||
}
|
||||
|
||||
builder.Append("\"");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// 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 GetDocument.Commands;
|
||||
using GetDocument.Properties;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static int Main(string[] args)
|
||||
{
|
||||
var app = new CommandLineApplication(throwOnUnexpectedArg: false)
|
||||
{
|
||||
FullName = Resources.CommandFullName,
|
||||
};
|
||||
|
||||
new InvokeCommand().Configure(app);
|
||||
|
||||
try
|
||||
{
|
||||
return app.Execute(args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is CommandException || ex is CommandParsingException)
|
||||
{
|
||||
Reporter.WriteVerbose(ex.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Reporter.WriteInformation(ex.ToString());
|
||||
}
|
||||
|
||||
Reporter.WriteError(ex.Message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
// 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.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using GetDocument.Properties;
|
||||
using IODirectory = System.IO.Directory;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal class Project
|
||||
{
|
||||
private const string MSBuildResourceName = "GetDocument.ServiceProjectReferenceMetadata";
|
||||
|
||||
private Project()
|
||||
{
|
||||
}
|
||||
|
||||
public string AssemblyName { get; private set; }
|
||||
|
||||
public string AssemblyPath { get; private set; }
|
||||
|
||||
public string AssetsPath { get; private set; }
|
||||
|
||||
public string Configuration { get; private set; }
|
||||
|
||||
public string ConfigPath { get; private set; }
|
||||
|
||||
public string DefaultDocumentName { get; private set; }
|
||||
|
||||
public string DefaultMethod { get; private set; }
|
||||
|
||||
public string DefaultService { get; private set; }
|
||||
|
||||
public string DefaultUri { get; private set; }
|
||||
|
||||
public string DepsPath { get; private set; }
|
||||
|
||||
public string Directory { get; private set; }
|
||||
|
||||
public string ExtensionsPath { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public string OutputPath { get; private set; }
|
||||
|
||||
public string Platform { get; private set; }
|
||||
|
||||
public string PlatformTarget { get; private set; }
|
||||
|
||||
public string RuntimeConfigPath { get; private set; }
|
||||
|
||||
public string RuntimeFrameworkVersion { get; private set; }
|
||||
|
||||
public string TargetFramework { get; private set; }
|
||||
|
||||
public string TargetFrameworkMoniker { get; private set; }
|
||||
|
||||
public static Project FromFile(
|
||||
string file,
|
||||
string buildExtensionsDirectory,
|
||||
string framework = null,
|
||||
string configuration = null,
|
||||
string runtime = null)
|
||||
{
|
||||
Debug.Assert(!string.IsNullOrEmpty(file), "file is null or empty.");
|
||||
|
||||
if (string.IsNullOrEmpty(buildExtensionsDirectory))
|
||||
{
|
||||
buildExtensionsDirectory = Path.Combine(Path.GetDirectoryName(file), "obj");
|
||||
}
|
||||
|
||||
IODirectory.CreateDirectory(buildExtensionsDirectory);
|
||||
|
||||
var assembly = typeof(Project).Assembly;
|
||||
var propsPath = Path.Combine(
|
||||
buildExtensionsDirectory,
|
||||
Path.GetFileName(file) + ".ServiceProjectReferenceMetadata.props");
|
||||
using (var input = assembly.GetManifestResourceStream($"{MSBuildResourceName}.props"))
|
||||
{
|
||||
using (var output = File.OpenWrite(propsPath))
|
||||
{
|
||||
Reporter.WriteVerbose(Resources.WritingFile(propsPath));
|
||||
input.CopyTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
var targetsPath = Path.ChangeExtension(propsPath, ".targets");
|
||||
using (var input = assembly.GetManifestResourceStream($"{MSBuildResourceName}.targets"))
|
||||
{
|
||||
using (var output = File.OpenWrite(targetsPath))
|
||||
{
|
||||
// NB: Copy always in case it changes
|
||||
Reporter.WriteVerbose(Resources.WritingFile(targetsPath));
|
||||
input.CopyTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
IDictionary<string, string> metadata;
|
||||
var metadataPath = Path.GetTempFileName();
|
||||
try
|
||||
{
|
||||
var propertyArg = "/property:ServiceProjectReferenceMetadataPath=" + metadataPath;
|
||||
if (!string.IsNullOrEmpty(framework))
|
||||
{
|
||||
propertyArg += ";TargetFramework=" + framework;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(configuration))
|
||||
{
|
||||
propertyArg += ";Configuration=" + configuration;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(runtime))
|
||||
{
|
||||
propertyArg += ";RuntimeIdentifier=" + runtime;
|
||||
}
|
||||
|
||||
var args = new List<string>
|
||||
{
|
||||
"msbuild",
|
||||
"/target:WriteServiceProjectReferenceMetadata",
|
||||
propertyArg,
|
||||
"/verbosity:quiet",
|
||||
"/nologo"
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(file))
|
||||
{
|
||||
args.Add(file);
|
||||
}
|
||||
|
||||
var exitCode = Exe.Run("dotnet", args);
|
||||
if (exitCode != 0)
|
||||
{
|
||||
throw new CommandException(Resources.GetMetadataFailed);
|
||||
}
|
||||
|
||||
metadata = File.ReadLines(metadataPath).Select(l => l.Split(new[] { ':' }, 2))
|
||||
.ToDictionary(s => s[0], s => s[1].TrimStart());
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(propsPath);
|
||||
File.Delete(metadataPath);
|
||||
File.Delete(targetsPath);
|
||||
}
|
||||
|
||||
var project = new Project
|
||||
{
|
||||
AssemblyName = metadata[nameof(AssemblyName)],
|
||||
AssemblyPath = metadata[nameof(AssemblyPath)],
|
||||
AssetsPath = metadata[nameof(AssetsPath)],
|
||||
Configuration = metadata[nameof(Configuration)],
|
||||
DefaultDocumentName = metadata[nameof(DefaultDocumentName)],
|
||||
DefaultMethod = metadata[nameof(DefaultMethod)],
|
||||
DefaultService = metadata[nameof(DefaultService)],
|
||||
DefaultUri = metadata[nameof(DefaultUri)],
|
||||
DepsPath = metadata[nameof(DepsPath)],
|
||||
Directory = metadata[nameof(Directory)],
|
||||
ExtensionsPath = metadata[nameof(ExtensionsPath)],
|
||||
Name = metadata[nameof(Name)],
|
||||
OutputPath = metadata[nameof(OutputPath)],
|
||||
Platform = metadata[nameof(Platform)],
|
||||
PlatformTarget = metadata[nameof(PlatformTarget)] ?? metadata[nameof(Platform)],
|
||||
RuntimeConfigPath = metadata[nameof(RuntimeConfigPath)],
|
||||
RuntimeFrameworkVersion = metadata[nameof(RuntimeFrameworkVersion)],
|
||||
TargetFramework = metadata[nameof(TargetFramework)],
|
||||
TargetFrameworkMoniker = metadata[nameof(TargetFrameworkMoniker)],
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(project.AssemblyPath))
|
||||
{
|
||||
throw new CommandException(Resources.GetMetadataValueFailed(nameof(AssemblyPath), "TargetPath"));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(project.Directory))
|
||||
{
|
||||
throw new CommandException(Resources.GetMetadataValueFailed(nameof(Directory), "ProjectDir"));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(project.OutputPath))
|
||||
{
|
||||
throw new CommandException(Resources.GetMetadataValueFailed(nameof(OutputPath), "OutDir"));
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(project.Directory))
|
||||
{
|
||||
project.Directory = Path.GetFullPath(Path.Combine(IODirectory.GetCurrentDirectory(), project.Directory));
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(project.AssemblyPath))
|
||||
{
|
||||
project.AssemblyPath = Path.GetFullPath(Path.Combine(project.Directory, project.AssemblyPath));
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(project.OutputPath))
|
||||
{
|
||||
project.OutputPath = Path.GetFullPath(Path.Combine(project.Directory, project.OutputPath));
|
||||
}
|
||||
|
||||
// Some document generation tools support non-ASP.NET Core projects.
|
||||
// Thus any of the remaining properties may be empty.
|
||||
if (!(string.IsNullOrEmpty(project.AssetsPath) || Path.IsPathRooted(project.AssetsPath)))
|
||||
{
|
||||
project.AssetsPath = Path.GetFullPath(Path.Combine(project.Directory, project.AssetsPath));
|
||||
}
|
||||
|
||||
var configPath = $"{project.AssemblyPath}.config";
|
||||
if (File.Exists(configPath))
|
||||
{
|
||||
project.ConfigPath = configPath;
|
||||
}
|
||||
|
||||
if (!(string.IsNullOrEmpty(project.DepsPath) || Path.IsPathRooted(project.DepsPath)))
|
||||
{
|
||||
project.DepsPath = Path.GetFullPath(Path.Combine(project.Directory, project.DepsPath));
|
||||
}
|
||||
|
||||
if (!(string.IsNullOrEmpty(project.RuntimeConfigPath) || Path.IsPathRooted(project.RuntimeConfigPath)))
|
||||
{
|
||||
project.RuntimeConfigPath = Path.GetFullPath(Path.Combine(project.Directory, project.RuntimeConfigPath));
|
||||
}
|
||||
|
||||
return project;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// 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 GetDocument.Properties;
|
||||
using Microsoft.DotNet.Cli.CommandLine;
|
||||
|
||||
namespace GetDocument
|
||||
{
|
||||
internal class ProjectOptions
|
||||
{
|
||||
public CommandOption Project { get; private set; }
|
||||
|
||||
public CommandOption Framework { get; private set; }
|
||||
|
||||
public CommandOption Configuration { get; private set; }
|
||||
|
||||
public CommandOption Runtime { get; private set; }
|
||||
|
||||
public CommandOption MSBuildProjectExtensionsPath { get; private set; }
|
||||
|
||||
public void Configure(CommandLineApplication command)
|
||||
{
|
||||
Project = command.Option("-p|--project <PROJECT>", Resources.ProjectDescription);
|
||||
Framework = command.Option("--framework <FRAMEWORK>", Resources.FrameworkDescription);
|
||||
Configuration = command.Option("--configuration <CONFIGURATION>", Resources.ConfigurationDescription);
|
||||
Runtime = command.Option("--runtime <RUNTIME_IDENTIFIER>", Resources.RuntimeDescription);
|
||||
MSBuildProjectExtensionsPath = command.Option("--msbuildprojectextensionspath <PATH>", Resources.ProjectExtensionsDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
// <auto-generated />
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace GetDocument.Properties
|
||||
{
|
||||
/// <summary>
|
||||
/// This API supports the GetDocument infrastructure and is not intended to be used
|
||||
/// directly from your code. This API may change or be removed in future releases.
|
||||
/// </summary>
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("GetDocument.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use.
|
||||
/// </summary>
|
||||
public static string ConfigurationDescription
|
||||
=> GetString("ConfigurationDescription");
|
||||
|
||||
/// <summary>
|
||||
/// dotnet getdocument
|
||||
/// </summary>
|
||||
public static string CommandFullName
|
||||
=> GetString("CommandFullName");
|
||||
|
||||
/// <summary>
|
||||
/// The target framework.
|
||||
/// </summary>
|
||||
public static string FrameworkDescription
|
||||
=> GetString("FrameworkDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option.
|
||||
/// </summary>
|
||||
public static string GetMetadataFailed
|
||||
=> GetString("GetMetadataFailed");
|
||||
|
||||
/// <summary>
|
||||
/// More than one project was found in the current working directory. Use the --project option.
|
||||
/// </summary>
|
||||
public static string MultipleProjects
|
||||
=> GetString("MultipleProjects");
|
||||
|
||||
/// <summary>
|
||||
/// More than one project was found in directory '{projectDirectory}'. Specify one using its file name.
|
||||
/// </summary>
|
||||
public static string MultipleProjectsInDirectory([CanBeNull] object projectDirectory)
|
||||
=> string.Format(
|
||||
GetString("MultipleProjectsInDirectory", nameof(projectDirectory)),
|
||||
projectDirectory);
|
||||
|
||||
/// <summary>
|
||||
/// Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the GetDocument Command-line Tool only supports version 2.0 or higher.
|
||||
/// </summary>
|
||||
public static string NETCoreApp1Project([CanBeNull] object Project, [CanBeNull] object targetFrameworkVersion)
|
||||
=> string.Format(
|
||||
GetString("NETCoreApp1Project", nameof(Project), nameof(targetFrameworkVersion)),
|
||||
Project, targetFrameworkVersion);
|
||||
|
||||
/// <summary>
|
||||
/// Project '{Project}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the GetDocument Command-line Tool with this project, add an executable project targeting .NET Core or .NET Framework that references this project and specify it using the --project option; or, update this project to target .NET Core and / or .NET Framework.
|
||||
/// </summary>
|
||||
public static string NETStandardProject([CanBeNull] object Project)
|
||||
=> string.Format(
|
||||
GetString("NETStandardProject", nameof(Project)),
|
||||
Project);
|
||||
|
||||
/// <summary>
|
||||
/// Do not colorize output.
|
||||
/// </summary>
|
||||
public static string NoColorDescription
|
||||
=> GetString("NoColorDescription");
|
||||
|
||||
/// <summary>
|
||||
/// No project was found. Change the current working directory or use the --project option.
|
||||
/// </summary>
|
||||
public static string NoProject
|
||||
=> GetString("NoProject");
|
||||
|
||||
/// <summary>
|
||||
/// No project was found in directory '{projectDirectory}'.
|
||||
/// </summary>
|
||||
public static string NoProjectInDirectory([CanBeNull] object projectDirectory)
|
||||
=> string.Format(
|
||||
GetString("NoProjectInDirectory", nameof(projectDirectory)),
|
||||
projectDirectory);
|
||||
|
||||
/// <summary>
|
||||
/// Prefix output with level.
|
||||
/// </summary>
|
||||
public static string PrefixDescription
|
||||
=> GetString("PrefixDescription");
|
||||
|
||||
/// <summary>
|
||||
/// The project to use.
|
||||
/// </summary>
|
||||
public static string ProjectDescription
|
||||
=> GetString("ProjectDescription");
|
||||
|
||||
/// <summary>
|
||||
/// The MSBuild project extensions path. Defaults to "obj".
|
||||
/// </summary>
|
||||
public static string ProjectExtensionsDescription
|
||||
=> GetString("ProjectExtensionsDescription");
|
||||
|
||||
/// <summary>
|
||||
/// The runtime identifier to use.
|
||||
/// </summary>
|
||||
public static string RuntimeDescription
|
||||
=> GetString("RuntimeDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Project '{Project}' targets framework '{targetFramework}'. The GetDocument Command-line Tool does not support this framework.
|
||||
/// </summary>
|
||||
public static string UnsupportedFramework([CanBeNull] object Project, [CanBeNull] object targetFramework)
|
||||
=> string.Format(
|
||||
GetString("UnsupportedFramework", nameof(Project), nameof(targetFramework)),
|
||||
Project, targetFramework);
|
||||
|
||||
/// <summary>
|
||||
/// Using project '{project}'.
|
||||
/// </summary>
|
||||
public static string UsingProject([CanBeNull] object project)
|
||||
=> string.Format(
|
||||
GetString("UsingProject", nameof(project)),
|
||||
project);
|
||||
|
||||
/// <summary>
|
||||
/// Show verbose output.
|
||||
/// </summary>
|
||||
public static string VerboseDescription
|
||||
=> GetString("VerboseDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Writing '{file}'...
|
||||
/// </summary>
|
||||
public static string WritingFile([CanBeNull] object file)
|
||||
=> string.Format(
|
||||
GetString("WritingFile", nameof(file)),
|
||||
file);
|
||||
|
||||
/// <summary>
|
||||
/// Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option.
|
||||
/// </summary>
|
||||
public static string MustBuild
|
||||
=> GetString("MustBuild");
|
||||
|
||||
/// <summary>
|
||||
/// The file to write the result to.
|
||||
/// </summary>
|
||||
public static string OutputDescription
|
||||
=> GetString("OutputDescription");
|
||||
|
||||
/// <summary>
|
||||
/// Unable to retrieve '{properrty}' project metadata. Ensure '{msbuildProperty}' is set.
|
||||
/// </summary>
|
||||
public static string GetMetadataValueFailed([CanBeNull] object properrty, [CanBeNull] object msbuildProperty)
|
||||
=> string.Format(
|
||||
GetString("GetMetadataValueFailed", nameof(properrty), nameof(msbuildProperty)),
|
||||
properrty, msbuildProperty);
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<#
|
||||
Session["ResourceFile"] = "Resources.resx";
|
||||
Session["AccessModifier"] = "internal";
|
||||
Session["NoDiagnostics"] = true;
|
||||
#>
|
||||
<#@ include file="..\..\tools\Resources.tt" #>
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ConfigurationDescription" xml:space="preserve">
|
||||
<value>The configuration to use.</value>
|
||||
</data>
|
||||
<data name="CommandFullName" xml:space="preserve">
|
||||
<value>dotnet getdocument</value>
|
||||
</data>
|
||||
<data name="FrameworkDescription" xml:space="preserve">
|
||||
<value>The target framework.</value>
|
||||
</data>
|
||||
<data name="GetMetadataFailed" xml:space="preserve">
|
||||
<value>Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option.</value>
|
||||
</data>
|
||||
<data name="MultipleProjects" xml:space="preserve">
|
||||
<value>More than one project was found in the current working directory. Use the --project option.</value>
|
||||
</data>
|
||||
<data name="MultipleProjectsInDirectory" xml:space="preserve">
|
||||
<value>More than one project was found in directory '{projectDirectory}'. Specify one using its file name.</value>
|
||||
</data>
|
||||
<data name="NETCoreApp1Project" xml:space="preserve">
|
||||
<value>Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the GetDocument Command-line Tool only supports version 2.0 or higher.</value>
|
||||
</data>
|
||||
<data name="NETStandardProject" xml:space="preserve">
|
||||
<value>Project '{Project}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the GetDocument Command-line Tool with this project, add an executable project targeting .NET Core or .NET Framework that references this project and specify it using the --project option; or, update this project to target .NET Core and / or .NET Framework.</value>
|
||||
</data>
|
||||
<data name="NoColorDescription" xml:space="preserve">
|
||||
<value>Do not colorize output.</value>
|
||||
</data>
|
||||
<data name="NoProject" xml:space="preserve">
|
||||
<value>No project was found. Change the current working directory or use the --project option.</value>
|
||||
</data>
|
||||
<data name="NoProjectInDirectory" xml:space="preserve">
|
||||
<value>No project was found in directory '{projectDirectory}'.</value>
|
||||
</data>
|
||||
<data name="PrefixDescription" xml:space="preserve">
|
||||
<value>Prefix output with level.</value>
|
||||
</data>
|
||||
<data name="ProjectDescription" xml:space="preserve">
|
||||
<value>The project to use.</value>
|
||||
</data>
|
||||
<data name="ProjectExtensionsDescription" xml:space="preserve">
|
||||
<value>The MSBuild project extensions path. Defaults to "obj".</value>
|
||||
</data>
|
||||
<data name="RuntimeDescription" xml:space="preserve">
|
||||
<value>The runtime identifier to use.</value>
|
||||
</data>
|
||||
<data name="UnsupportedFramework" xml:space="preserve">
|
||||
<value>Project '{Project}' targets framework '{targetFramework}'. The GetDocument Command-line Tool does not support this framework.</value>
|
||||
</data>
|
||||
<data name="UsingProject" xml:space="preserve">
|
||||
<value>Using project '{project}'.</value>
|
||||
</data>
|
||||
<data name="VerboseDescription" xml:space="preserve">
|
||||
<value>Show verbose output.</value>
|
||||
</data>
|
||||
<data name="WritingFile" xml:space="preserve">
|
||||
<value>Writing '{file}'...</value>
|
||||
</data>
|
||||
<data name="MustBuild" xml:space="preserve">
|
||||
<value>Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option.</value>
|
||||
</data>
|
||||
<data name="OutputDescription" xml:space="preserve">
|
||||
<value>The file to write the result to.</value>
|
||||
</data>
|
||||
<data name="GetMetadataValueFailed" xml:space="preserve">
|
||||
<value>Unable to retrieve '{properrty}' project metadata. Ensure '{msbuildProperty}' is set.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- No need for any additional work in outer build. -->
|
||||
<WriteServiceProjectReferenceMetadataDependsOn Condition="'$(TargetFramework)' != '' AND '$(WriteServiceProjectReferenceMetadataDependsOn)' == ''">
|
||||
$(WriteServiceProjectReferenceMetadataDependsOn)
|
||||
</WriteServiceProjectReferenceMetadataDependsOn>
|
||||
|
||||
<!-- Execute WriteServiceProjectReferenceMetadata support targets after WriteServiceProjectReferenceMetadataDependsOn targets by default. -->
|
||||
<GetServiceProjectReferenceMetadataDependsOn Condition="'$(GetServiceProjectReferenceMetadataDependsOn)' == ''">
|
||||
$(WriteServiceProjectReferenceMetadataDependsOn)
|
||||
</GetServiceProjectReferenceMetadataDependsOn>
|
||||
<WriteServiceProjectReferenceMetadataCoreDependsOn Condition="'$(WriteServiceProjectReferenceMetadataCoreDependsOn)' == ''">
|
||||
$(WriteServiceProjectReferenceMetadataDependsOn)
|
||||
</WriteServiceProjectReferenceMetadataCoreDependsOn>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="WriteServiceProjectReferenceMetadata"
|
||||
DependsOnTargets="$(WriteServiceProjectReferenceMetadataDependsOn)"
|
||||
Returns="@(ServiceProjectReferenceMetadata)" />
|
||||
|
||||
<!-- Collect properties only in inner build. Execute unconditionally before WriteServiceProjectReferenceMetadataCore. -->
|
||||
<Target Name="GetServiceProjectReferenceMetadata"
|
||||
BeforeTargets="WriteServiceProjectReferenceMetadataCore"
|
||||
Condition="'$(TargetFramework)' != ''"
|
||||
DependsOnTargets="$(GetServiceProjectReferenceMetadataDependsOn)"
|
||||
Returns="@(ServiceProjectReferenceMetadata)">
|
||||
<ItemGroup Condition="'$(TargetFramework)' != ''">
|
||||
<ServiceProjectReferenceMetadata Include="DefaultDocumentName: $(DefaultServiceProjectDocumentName)" />
|
||||
<ServiceProjectReferenceMetadata Include="DefaultMethod: $(DefaultServiceProjectMethod)"></ServiceProjectReferenceMetadata>
|
||||
<ServiceProjectReferenceMetadata Include="DefaultService: $(DefaultServiceProjectService)"></ServiceProjectReferenceMetadata>
|
||||
<ServiceProjectReferenceMetadata Include="DefaultUri: $(DefaultServiceProjectUri)"></ServiceProjectReferenceMetadata>
|
||||
|
||||
<ServiceProjectReferenceMetadata Include="AssemblyName: $(AssemblyName)" />
|
||||
<ServiceProjectReferenceMetadata Include="AssemblyPath: $(TargetPath)" />
|
||||
<ServiceProjectReferenceMetadata Include="AssetsPath: $(ProjectAssetsFile)" />
|
||||
<ServiceProjectReferenceMetadata Include="Configuration: $(Configuration)" />
|
||||
<ServiceProjectReferenceMetadata Include="DepsPath: $(ProjectDepsFilePath)" />
|
||||
<ServiceProjectReferenceMetadata Include="Directory: $(ProjectDir)" />
|
||||
<ServiceProjectReferenceMetadata Include="ExtensionsPath: $(MSBuildProjectExtensionsPath)" />
|
||||
<ServiceProjectReferenceMetadata Include="Name: $(MSBuildProjectName)" />
|
||||
<ServiceProjectReferenceMetadata Include="OutputPath: $(OutDir)" />
|
||||
<ServiceProjectReferenceMetadata Include="Platform: $(Platform)" />
|
||||
<ServiceProjectReferenceMetadata Include="PlatformTarget: $(PlatformTarget)" />
|
||||
<ServiceProjectReferenceMetadata Include="RuntimeConfigPath: $(ProjectRuntimeConfigFilePath)" />
|
||||
<ServiceProjectReferenceMetadata Include="RuntimeFrameworkVersion: $(RuntimeFrameworkVersion)" />
|
||||
<ServiceProjectReferenceMetadata Include="TargetFramework: $(TargetFramework)" />
|
||||
<ServiceProjectReferenceMetadata Include="TargetFrameworkMoniker: $(TargetFrameworkMoniker)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<!-- Write information only in inner build. Execute unconditionally before WriteServiceProjectReferenceMetadata. -->
|
||||
<Target Name="WriteServiceProjectReferenceMetadataCore"
|
||||
BeforeTargets="WriteServiceProjectReferenceMetadata"
|
||||
DependsOnTargets="$(WriteServiceProjectReferenceMetadataCoreDependsOn)"
|
||||
Returns="@(ServiceProjectReferenceMetadata)">
|
||||
<MSBuild Condition="'$(TargetFramework)' == ''"
|
||||
Projects="$(MSBuildProjectFile)"
|
||||
Targets="WriteServiceProjectReferenceMetadata"
|
||||
Properties="TargetFramework=$(TargetFrameworks.Split(';')[0]);ServiceProjectReferenceMetadataFile=$(ServiceProjectReferenceMetadataFile)" />
|
||||
|
||||
<WriteLinesToFile Condition="'$(TargetFramework)' != ''" File="$(ServiceProjectReferenceMetadataPath)" Lines="@(ServiceProjectReferenceMetadata)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
<Project>
|
||||
<Sdk Name="Microsoft.NET.Sdk" />
|
||||
<!-- Sdk Name="Microsoft.DotNet.GlobalTools.Sdk" / -->
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Execute PopulateNuspec fairly late. -->
|
||||
<GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);PopulateNuspec</GenerateNuspecDependsOn>
|
||||
|
||||
<AssemblyName>dotnet-getdocument</AssemblyName>
|
||||
<Description>GetDocument Command-line Tool outside man</Description>
|
||||
<EnableApiCheck>false</EnableApiCheck>
|
||||
<GenerateToolShims>true</GenerateToolShims>
|
||||
<IncludeSource>false</IncludeSource>
|
||||
<IsPackable>false</IsPackable>
|
||||
<NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PackAsTool>true</PackAsTool>
|
||||
<PackageTags>GetDocument;command line;command-line;tool</PackageTags>
|
||||
<RootNamespace>GetDocument</RootNamespace>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="../GetDocumentInsider/AnsiConsole.cs" />
|
||||
<Compile Include="../GetDocumentInsider/AnsiConstants.cs" />
|
||||
<Compile Include="../GetDocumentInsider/AnsiTextWriter.cs" />
|
||||
<Compile Include="../GetDocumentInsider/CodeAnnotations.cs" />
|
||||
<Compile Include="../GetDocumentInsider/CommandException.cs" />
|
||||
<Compile Include="../GetDocumentInsider/CommandLineUtils/*.cs" LinkBase="CommandLineUtils" />
|
||||
<Compile Include="../GetDocumentInsider/Commands/CommandBase.cs" Link="Commands/CommandBase.cs" />
|
||||
<Compile Include="../GetDocumentInsider/Commands/HelpCommandBase.cs" Link="Commands/HelpCommandBase.cs" />
|
||||
<Compile Include="../GetDocumentInsider/ProductInfo.cs" />
|
||||
<Compile Include="../GetDocumentInsider/Reporter.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ServiceProjectReferenceMetadata.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Properties/Resources.Designer.tt">
|
||||
<Generator>TextTemplatingFileGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties/Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.Designer.tt</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Additional files to be code signed -->
|
||||
<SignedPackageFile Include="tools/netcoreapp2.1/any/tools/net461/any/GetDocument.Insider.exe" Certificate="$(AssemblySigningCertName)" />
|
||||
<SignedPackageFile Include="tools/netcoreapp2.1/any/tools/net461/win-x86/GetDocument.Insider.exe" Certificate="$(AssemblySigningCertName)" />
|
||||
<SignedPackageFile Include="tools/netcoreapp2.1/any/tools/netcoreapp2.0/any/GetDocument.Insider.dll" Certificate="$(AssemblySigningCertName)" />
|
||||
|
||||
<!-- Third-party assemblies should be signed with the 3PartyDual certificate -->
|
||||
<SignedPackageFile Include="tools/netcoreapp2.1/any/Newtonsoft.Json.dll" Certificate="3PartyDual" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PopulateNuspec" DependsOnTargets="Build">
|
||||
<ItemGroup>
|
||||
<_Temporary Remove="@(Temporary)" />
|
||||
<_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=net461" />
|
||||
<_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=net461;Platform=x86" />
|
||||
<_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=netcoreapp2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<MSBuild Projects="../GetDocumentInsider/GetDocumentInsider.csproj" RemoveProperties="RuntimeIdentifier;TargetFramework" Targets="Restore" />
|
||||
<MSBuild Projects="@(_Temporary)" BuildInParallel="$(BuildInParallel)" RemoveProperties="RuntimeIdentifier" Targets="Publish" />
|
||||
|
||||
<ItemGroup>
|
||||
<_Temporary Remove="@(_Temporary)" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<NuspecProperties>
|
||||
authors=$(Authors);
|
||||
copyright=$(Copyright);
|
||||
description=$(Description);
|
||||
iconUrl=$(PackageIconUrl);
|
||||
id=$(PackageId);
|
||||
InsiderNet461Output=..\GetDocumentInsider\bin\$(Configuration)\net461\publish\*;
|
||||
InsiderNet461X86Output=..\GetDocumentInsider\bin\x86\$(Configuration)\net461\publish\*;
|
||||
InsiderNetCoreOutput=..\GetDocumentInsider\bin\$(Configuration)\netcoreapp2.0\publish\*;
|
||||
licenseUrl=$(PackageLicenseUrl);
|
||||
Output=$(PublishDir)**\*;
|
||||
OutputShims=$(IntermediateOutputPath)shims\**\*;
|
||||
packageType=$(PackageType);
|
||||
projectUrl=$(PackageProjectUrl);
|
||||
repositoryCommit=$(RepositoryCommit);
|
||||
repositoryUrl=$(RepositoryUrl);
|
||||
SettingsFile=$(_ToolsSettingsFilePath);
|
||||
tags=$(PackageTags.Replace(';', ' '));
|
||||
targetFramework=$(TargetFramework);
|
||||
version=$(PackageVersion);
|
||||
</NuspecProperties>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<version>$version$</version>
|
||||
<authors>$authors$</authors>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<licenseUrl>$licenseUrl$</licenseUrl>
|
||||
<projectUrl>$projectUrl$</projectUrl>
|
||||
<iconUrl>$iconUrl$</iconUrl>
|
||||
<description>$description$</description>
|
||||
<copyright>$copyright$</copyright>
|
||||
<tags>$tags$</tags>
|
||||
<packageTypes>
|
||||
<packageType name="$packageType$" />
|
||||
</packageTypes>
|
||||
<repository type="git" url="$repositoryUrl$" commit="$repositoryCommit$" />
|
||||
</metadata>
|
||||
|
||||
<files>
|
||||
<file src="$InsiderNet461Output$" target="tools\$targetFramework$\any\net461" />
|
||||
<file src="$InsiderNet461X86Output$" target="tools\$targetFramework$\any\net461-x86" />
|
||||
<file src="$InsiderNetCoreOutput$" target="tools\$targetFramework$\any\netcoreapp2.0" />
|
||||
<file src="$Output$" target="tools\$targetFramework$\any" />
|
||||
<!-- file src="$OutputShims$" target="tools\$targetFramework$\any\shims" / -->
|
||||
<file src="$SettingsFile$" target="tools\$targetFramework$\any" />
|
||||
</files>
|
||||
</package>
|
||||
Loading…
Reference in New Issue