Merge pull request #8585 from aspnet/feature/client.code.generation
Merge feature/client.code.generation branch into release/2.2
This commit is contained in:
commit
18acae77c8
|
|
@ -117,6 +117,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ap
|
||||||
EndProject
|
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}"
|
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
|
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.Design", "src\Microsoft.Extensions.ApiDescription.Design\Microsoft.Extensions.ApiDescription.Design.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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|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.ActiveCfg = Release|Any CPU
|
||||||
{71C626FC-6408-494B-A127-38CB64F71324}.Release|x86.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -619,6 +661,9 @@ Global
|
||||||
{92D959F2-66B8-490A-BA33-DA4421EBC948} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
{92D959F2-66B8-490A-BA33-DA4421EBC948} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||||
{1B398182-9EAE-400B-A2BD-EFFAC0168A36} = {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}
|
{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
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {D003597F-372F-4068-A2F0-353BE3C3B39A}
|
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
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorRendering", "benchmarkapps\RazorRendering\RazorRendering.csproj", "{D7C6A696-F232-4288-BCCD-367407E4A934}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorRendering", "benchmarkapps\RazorRendering\RazorRendering.csproj", "{D7C6A696-F232-4288-BCCD-367407E4A934}"
|
||||||
EndProject
|
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.Design", "src\Microsoft.Extensions.ApiDescription.Design\Microsoft.Extensions.ApiDescription.Design.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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|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.ActiveCfg = Release|Any CPU
|
||||||
{D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -1010,6 +1052,9 @@ Global
|
||||||
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
{DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||||
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
{3B550487-10E4-4E6D-9CEF-B1B4CA1253DA} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||||
{D7C6A696-F232-4288-BCCD-367407E4A934} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E}
|
{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
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A}
|
SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,31 @@
|
||||||
{
|
{
|
||||||
"Default": {
|
"Default": {
|
||||||
"rules": [
|
"rules": [
|
||||||
"DefaultCompositeRule"
|
"DefaultCompositeRule"
|
||||||
]
|
],
|
||||||
|
"packages": {
|
||||||
|
"Microsoft.Extensions.ApiDescription.Design": {
|
||||||
|
"Exclusions": {
|
||||||
|
"BUILD_ITEMS_FRAMEWORK": {
|
||||||
|
"*": "Package includes tool with different target frameworks."
|
||||||
|
},
|
||||||
|
"SERVICING_ATTRIBUTE": {
|
||||||
|
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
|
||||||
|
},
|
||||||
|
"WRONG_PUBLICKEYTOKEN": {
|
||||||
|
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
|
||||||
|
},
|
||||||
|
"ASSEMBLY_INFORMATIONAL_VERSION_MISMATCH": {
|
||||||
|
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
|
||||||
|
},
|
||||||
|
"ASSEMBLY_FILE_VERSION_MISMATCH": {
|
||||||
|
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
|
||||||
|
},
|
||||||
|
"ASSEMBLY_VERSION_MISMATCH": {
|
||||||
|
"tools/Newtonsoft.Json.dll": "External assembly, not built as part of this process"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
is not otherwise referenced. They avoid unnecessary changes to the Universe build graph or to product
|
is not otherwise referenced. They avoid unnecessary changes to the Universe build graph or to product
|
||||||
dependencies. Do not use these properties elsewhere.
|
dependencies. Do not use these properties elsewhere.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>
|
<AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>
|
||||||
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
|
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
|
||||||
<BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion>2.1.1</BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion>
|
<BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion>2.1.1</BenchmarksOnlyMicrosoftEntityFrameworkCoreDesignPackageVersion>
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
|
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
|
||||||
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreDiagnosticsPackageVersion>
|
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreDiagnosticsPackageVersion>
|
||||||
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
|
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
|
||||||
|
<MicrosoftAspNetCoreHostingAbstractions20PackageVersion>2.0.0</MicrosoftAspNetCoreHostingAbstractions20PackageVersion>
|
||||||
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHostingPackageVersion>
|
<MicrosoftAspNetCoreHostingPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHostingPackageVersion>
|
||||||
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
|
<MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHtmlAbstractionsPackageVersion>
|
||||||
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
|
<MicrosoftAspNetCoreHttpExtensionsPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreHttpExtensionsPackageVersion>
|
||||||
|
|
@ -57,6 +58,7 @@
|
||||||
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreTestingPackageVersion>
|
<MicrosoftAspNetCoreTestingPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreTestingPackageVersion>
|
||||||
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
|
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview3-35359</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
|
||||||
<MicrosoftAspNetWebApiClientPackageVersion>5.2.6</MicrosoftAspNetWebApiClientPackageVersion>
|
<MicrosoftAspNetWebApiClientPackageVersion>5.2.6</MicrosoftAspNetWebApiClientPackageVersion>
|
||||||
|
<MicrosoftBuildUtilitiesCorePackageVersion>15.6.82</MicrosoftBuildUtilitiesCorePackageVersion>
|
||||||
<MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion>
|
<MicrosoftCodeAnalysisCSharpPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpPackageVersion>
|
||||||
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
|
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>2.8.0</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
|
||||||
<MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-preview3-35359</MicrosoftCodeAnalysisRazorPackageVersion>
|
<MicrosoftCodeAnalysisRazorPackageVersion>2.2.0-preview3-35359</MicrosoftCodeAnalysisRazorPackageVersion>
|
||||||
|
|
@ -100,8 +102,10 @@
|
||||||
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
<MoqPackageVersion>4.7.49</MoqPackageVersion>
|
||||||
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
|
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
|
||||||
<NewtonsoftJsonBsonPackageVersion>1.0.1</NewtonsoftJsonBsonPackageVersion>
|
<NewtonsoftJsonBsonPackageVersion>1.0.1</NewtonsoftJsonBsonPackageVersion>
|
||||||
|
<NewtonsoftJsonPackageVersion>11.0.2</NewtonsoftJsonPackageVersion>
|
||||||
<SystemComponentModelAnnotationsPackageVersion>4.5.0</SystemComponentModelAnnotationsPackageVersion>
|
<SystemComponentModelAnnotationsPackageVersion>4.5.0</SystemComponentModelAnnotationsPackageVersion>
|
||||||
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.0</SystemDiagnosticsDiagnosticSourcePackageVersion>
|
<SystemDiagnosticsDiagnosticSourcePackageVersion>4.5.0</SystemDiagnosticsDiagnosticSourcePackageVersion>
|
||||||
|
<SystemNetHttpPackageVersion>4.3.2</SystemNetHttpPackageVersion>
|
||||||
<SystemThreadingTasksExtensionsPackageVersion>4.5.1</SystemThreadingTasksExtensionsPackageVersion>
|
<SystemThreadingTasksExtensionsPackageVersion>4.5.1</SystemThreadingTasksExtensionsPackageVersion>
|
||||||
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
|
<XunitAnalyzersPackageVersion>0.10.0</XunitAnalyzersPackageVersion>
|
||||||
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
<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 Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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 Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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 Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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,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 Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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,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 Microsoft.DotNet.Cli.CommandLine;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool.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,167 @@
|
||||||
|
// 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 Microsoft.DotNet.Cli.CommandLine;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
|
||||||
|
{
|
||||||
|
internal class GetDocumentCommand : ProjectCommandBase
|
||||||
|
{
|
||||||
|
internal const string FallbackDocumentName = "v1";
|
||||||
|
internal const string FallbackMethod = "Generate";
|
||||||
|
internal const string FallbackService = "Microsoft.Extensions.ApiDescription.IDocumentProvider";
|
||||||
|
|
||||||
|
private CommandOption _documentName;
|
||||||
|
private CommandOption _method;
|
||||||
|
private CommandOption _output;
|
||||||
|
private CommandOption _service;
|
||||||
|
|
||||||
|
public override void Configure(CommandLineApplication command)
|
||||||
|
{
|
||||||
|
base.Configure(command);
|
||||||
|
|
||||||
|
_documentName = command.Option(
|
||||||
|
"--documentName <Name>",
|
||||||
|
Resources.FormatDocumentDescription(FallbackDocumentName));
|
||||||
|
_method = command.Option("--method <Name>", Resources.FormatMethodDescription(FallbackMethod));
|
||||||
|
_output = command.Option("--output <Path>", Resources.OutputDescription);
|
||||||
|
_service = command.Option("--service <QualifiedName>", Resources.FormatServiceDescription(FallbackService));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Validate()
|
||||||
|
{
|
||||||
|
base.Validate();
|
||||||
|
|
||||||
|
if (!_output.HasValue())
|
||||||
|
{
|
||||||
|
throw new CommandException(Resources.FormatMissingOption(_output.LongName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_method.HasValue() && !_service.HasValue())
|
||||||
|
{
|
||||||
|
throw new CommandException(Resources.FormatMissingOption(_service.LongName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_service.HasValue() && !_method.HasValue())
|
||||||
|
{
|
||||||
|
throw new CommandException(Resources.FormatMissingOption(_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 the application's code.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return GetDocumentCommandWorker.Process(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,25 @@
|
||||||
|
// 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.Extensions.ApiDescription.Tool.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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
// 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.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool.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.FormatMissingEntryPoint(context.AssemblyPath));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var services = GetServices(entryPointType, context.AssemblyPath, context.AssemblyName);
|
||||||
|
if (services == null)
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
var success = TryProcess(context, services);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
// As part of the aspnet/Mvc#8425 fix, return 4 here.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.FormatUsingDocument(documentName));
|
||||||
|
Reporter.WriteInformation(Resources.FormatUsingMethod(methodName));
|
||||||
|
Reporter.WriteInformation(Resources.FormatUsingService(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)
|
||||||
|
{
|
||||||
|
// As part of the aspnet/Mvc#8425 fix, make this an error unless the file already exists.
|
||||||
|
var message = Resources.FormatMethodInvocationFailed(methodName, serviceName, documentName);
|
||||||
|
Reporter.WriteWarning(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var message = FormatException(ex);
|
||||||
|
|
||||||
|
// As part of the aspnet/Mvc#8425 fix, make this an error unless the file already exists.
|
||||||
|
Reporter.WriteWarning(message);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Microsoft.Extensions.ApiDescription.Tool.Commands
|
||||||
|
{
|
||||||
|
internal class HelpCommandBase : CommandBase
|
||||||
|
{
|
||||||
|
public override void Configure(CommandLineApplication command)
|
||||||
|
{
|
||||||
|
base.Configure(command);
|
||||||
|
|
||||||
|
command.HelpOption("-h|--help");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// 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 Microsoft.Extensions.ApiDescription.Tool.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.FormatMissingOption(AssemblyPath.LongName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ToolsDirectory.HasValue())
|
||||||
|
{
|
||||||
|
throw new CommandException(Resources.FormatMissingOption(ToolsDirectory.LongName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<Project Sdk="Internal.AspNetCore.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyName>GetDocument.Insider</AssemblyName>
|
||||||
|
<Description>GetDocument Command-line Tool inside man</Description>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Microsoft.Extensions.ApiDescription.Tool</RootNamespace>
|
||||||
|
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(MicrosoftAspNetCoreHostingAbstractions20PackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="BuildX86" AfterTargets="Build" Condition=" '$(TargetFramework)' == 'net461' And '$(Platform)' != 'x86' ">
|
||||||
|
<MSBuild Projects="$(MSBuildProjectFullPath)" Properties="TargetFramework=$(TargetFramework);Platform=x86" Targets="Build" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// 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 Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
internal static class ProductInfo
|
||||||
|
{
|
||||||
|
public static string GetVersion()
|
||||||
|
=> typeof(ProductInfo)
|
||||||
|
.Assembly
|
||||||
|
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
|
||||||
|
.InformationalVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// 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 Microsoft.DotNet.Cli.CommandLine;
|
||||||
|
using Microsoft.Extensions.ApiDescription.Tool.Commands;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Reporter.WriteVerbose(ex.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Reporter.WriteInformation(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Reporter.WriteError(ex.Message);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,240 @@
|
||||||
|
// <auto-generated />
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
|
||||||
|
internal static class Resources
|
||||||
|
{
|
||||||
|
private static readonly ResourceManager _resourceManager
|
||||||
|
= new ResourceManager("Microsoft.Extensions.ApiDescription.Tool.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The assembly to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string AssemblyDescription
|
||||||
|
{
|
||||||
|
get => GetString("AssemblyDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The assembly to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatAssemblyDescription()
|
||||||
|
=> GetString("AssemblyDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Missing required option '--{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MissingOption
|
||||||
|
{
|
||||||
|
get => GetString("MissingOption");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Missing required option '--{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMissingOption(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("MissingOption"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do not colorize output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string NoColorDescription
|
||||||
|
{
|
||||||
|
get => GetString("NoColorDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do not colorize output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatNoColorDescription()
|
||||||
|
=> GetString("NoColorDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The file to write the result to.
|
||||||
|
/// </summary>
|
||||||
|
internal static string OutputDescription
|
||||||
|
{
|
||||||
|
get => GetString("OutputDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The file to write the result to.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatOutputDescription()
|
||||||
|
=> GetString("OutputDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix console output with logging level.
|
||||||
|
/// </summary>
|
||||||
|
internal static string PrefixDescription
|
||||||
|
{
|
||||||
|
get => GetString("PrefixDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix console output with logging level.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatPrefixDescription()
|
||||||
|
=> GetString("PrefixDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show verbose output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string VerboseDescription
|
||||||
|
{
|
||||||
|
get => GetString("VerboseDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show verbose output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatVerboseDescription()
|
||||||
|
=> GetString("VerboseDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Location from which inside man was copied (in the .NET Framework case) or loaded.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ToolsDirectoryDescription
|
||||||
|
{
|
||||||
|
get => GetString("ToolsDirectoryDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Location from which inside man was copied (in the .NET Framework case) or loaded.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatToolsDirectoryDescription()
|
||||||
|
=> GetString("ToolsDirectoryDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the method to invoke on the '--service' instance. Default value '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MethodDescription
|
||||||
|
{
|
||||||
|
get => GetString("MethodDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the method to invoke on the '--service' instance. Default value '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMethodDescription(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodDescription"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The qualified name of the service type to retrieve from dependency injection. Default value '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceDescription
|
||||||
|
{
|
||||||
|
get => GetString("ServiceDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The qualified name of the service type to retrieve from dependency injection. Default value '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatServiceDescription(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("ServiceDescription"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the document to pass to the '--method' method. Default value '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DocumentDescription
|
||||||
|
{
|
||||||
|
get => GetString("DocumentDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the document to pass to the '--method' method. Default value '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatDocumentDescription(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("DocumentDescription"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using document name '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string UsingDocument
|
||||||
|
{
|
||||||
|
get => GetString("UsingDocument");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using document name '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatUsingDocument(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("UsingDocument"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using method '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string UsingMethod
|
||||||
|
{
|
||||||
|
get => GetString("UsingMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using method '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatUsingMethod(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("UsingMethod"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using service '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string UsingService
|
||||||
|
{
|
||||||
|
get => GetString("UsingService");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using service '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatUsingService(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("UsingService"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method '{0}' of service '{1}' failed to generate document '{2}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MethodInvocationFailed
|
||||||
|
{
|
||||||
|
get => GetString("MethodInvocationFailed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method '{0}' of service '{1}' failed to generate document '{2}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMethodInvocationFailed(object p0, object p1, object p2)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("MethodInvocationFailed"), p0, p1, p2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assembly '{0}' does not contain an entry point.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MissingEntryPoint
|
||||||
|
{
|
||||||
|
get => GetString("MissingEntryPoint");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assembly '{0}' does not contain an entry point.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMissingEntryPoint(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("MissingEntryPoint"), p0);
|
||||||
|
|
||||||
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
|
{
|
||||||
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.Assert(value != null);
|
||||||
|
|
||||||
|
if (formatterNames != null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < formatterNames.Length; i++)
|
||||||
|
{
|
||||||
|
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 Microsoft.Extensions.ApiDescription.Tool.AnsiConstants;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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,165 @@
|
||||||
|
<?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="MissingOption" xml:space="preserve">
|
||||||
|
<value>Missing required option '--{0}'.</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="VerboseDescription" xml:space="preserve">
|
||||||
|
<value>Show verbose output.</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="MethodDescription" xml:space="preserve">
|
||||||
|
<value>The name of the method to invoke on the '--service' instance. Default value '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ServiceDescription" xml:space="preserve">
|
||||||
|
<value>The qualified name of the service type to retrieve from dependency injection. Default value '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DocumentDescription" xml:space="preserve">
|
||||||
|
<value>The name of the document to pass to the '--method' method. Default value '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="UsingDocument" xml:space="preserve">
|
||||||
|
<value>Using document name '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="UsingMethod" xml:space="preserve">
|
||||||
|
<value>Using method '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="UsingService" xml:space="preserve">
|
||||||
|
<value>Using service '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="MethodInvocationFailed" xml:space="preserve">
|
||||||
|
<value>Method '{0}' of service '{1}' failed to generate document '{2}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="MissingEntryPoint" xml:space="preserve">
|
||||||
|
<value>Assembly '{0}' does not contain an entry point.</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
using System;
|
// 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.AspNetCore.Mvc.Razor
|
namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
// 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.Net.Sockets;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
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 Microsoft.Extensions.ApiDescription.Tasks
|
||||||
|
{
|
||||||
|
/// <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(MessageImportance.High, $"Downloading '{uri}' to '{destinationPath}'.");
|
||||||
|
|
||||||
|
using (var httpClient = new HttpClient())
|
||||||
|
{
|
||||||
|
await DownloadAsync(uri, destinationPath, httpClient, cancellationToken, log, timeoutSeconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task DownloadAsync(
|
||||||
|
string uri,
|
||||||
|
string destinationPath,
|
||||||
|
HttpClient httpClient,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
TaskLoggingHelper log,
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (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.Length == destinationHash.Length;
|
||||||
|
for (var i = 0; sameHashes && i < downloadHash.Length; i++)
|
||||||
|
{
|
||||||
|
sameHashes = downloadHash[i] == destinationHash[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sameHashes)
|
||||||
|
{
|
||||||
|
log.LogMessage($"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.CreateDirectory(destinationDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or overwrite the destination file.
|
||||||
|
reachedCopy = true;
|
||||||
|
using (var outStream = File.Create(destinationPath))
|
||||||
|
{
|
||||||
|
await responseStream.CopyToAsync(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.LogErrorFromException(ex, showStackTrace: true);
|
||||||
|
if (reachedCopy)
|
||||||
|
{
|
||||||
|
File.Delete(destinationPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetHash(Stream stream)
|
||||||
|
{
|
||||||
|
SHA256 algorithm;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
algorithm = SHA256.Create();
|
||||||
|
}
|
||||||
|
catch (TargetInvocationException)
|
||||||
|
{
|
||||||
|
// SHA256.Create is documented to throw this exception on FIPS-compliant machines. See
|
||||||
|
// https://msdn.microsoft.com/en-us/library/z08hz7ad Fall back to a FIPS-compliant SHA256 algorithm.
|
||||||
|
algorithm = new SHA256CryptoServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
using (algorithm)
|
||||||
|
{
|
||||||
|
return algorithm.ComputeHash(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Restore <see cref="ITaskItem"/>s from given property value.
|
||||||
|
/// </summary>
|
||||||
|
public class GetCurrentItems : Task
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The property value to deserialize.
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string Input { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The restored <see cref="ITaskItem"/>s. Will never contain more than one item.
|
||||||
|
/// </summary>
|
||||||
|
[Output]
|
||||||
|
public ITaskItem[] Outputs { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
Outputs = new[] { MetadataSerializer.DeserializeMetadata(Input) };
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
// 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 Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or corrects ClassName, Namespace and OutputPath metadata in ServiceFileReference items. Also stores final
|
||||||
|
/// metadata as SerializedMetadata.
|
||||||
|
/// </summary>
|
||||||
|
public class GetFileReferenceMetadata : Task
|
||||||
|
{
|
||||||
|
private const string TypeScriptLanguageName = "TypeScript";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension to use in default OutputPath metadata value. Ignored when generating TypeScript.
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string Extension { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default Namespace metadata value.
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public string Namespace { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default directory for OutputPath values.
|
||||||
|
/// </summary>
|
||||||
|
public string OutputDirectory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ServiceFileReference items to update.
|
||||||
|
/// </summary>
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] Inputs { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The updated ServiceFileReference items. Will include ClassName, Namespace and OutputPath metadata.
|
||||||
|
/// </summary>
|
||||||
|
[Output]
|
||||||
|
public ITaskItem[] Outputs{ get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool Execute()
|
||||||
|
{
|
||||||
|
var outputs = new List<ITaskItem>(Inputs.Length);
|
||||||
|
var destinations = new HashSet<string>();
|
||||||
|
|
||||||
|
foreach (var item in Inputs)
|
||||||
|
{
|
||||||
|
var newItem = new TaskItem(item);
|
||||||
|
outputs.Add(newItem);
|
||||||
|
|
||||||
|
var codeGenerator = item.GetMetadata("CodeGenerator");
|
||||||
|
if (string.IsNullOrEmpty("CodeGenerator"))
|
||||||
|
{
|
||||||
|
// This case occurs when user forgets to specify the required metadata. We have no default here.
|
||||||
|
string type;
|
||||||
|
if (!string.IsNullOrEmpty(item.GetMetadata("SourceProject")))
|
||||||
|
{
|
||||||
|
type = "ServiceProjectReference";
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(item.GetMetadata("SourceUri")))
|
||||||
|
{
|
||||||
|
type = "ServiceUriReference";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = "ServiceFileReference";
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.LogError(Resources.FormatInvalidEmptyMetadataValue("CodeGenerator", type, item.ItemSpec));
|
||||||
|
}
|
||||||
|
|
||||||
|
var className = item.GetMetadata("ClassName");
|
||||||
|
if (string.IsNullOrEmpty(className))
|
||||||
|
{
|
||||||
|
var filename = item.GetMetadata("Filename");
|
||||||
|
className = $"{filename}Client";
|
||||||
|
if (char.IsLower(className[0]))
|
||||||
|
{
|
||||||
|
className = char.ToUpper(className[0]) + className.Substring(startIndex: 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MetadataSerializer.SetMetadata(newItem, "ClassName", className);
|
||||||
|
}
|
||||||
|
|
||||||
|
var @namespace = item.GetMetadata("Namespace");
|
||||||
|
if (string.IsNullOrEmpty(@namespace))
|
||||||
|
{
|
||||||
|
MetadataSerializer.SetMetadata(newItem, "Namespace", Namespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputPath = item.GetMetadata("OutputPath");
|
||||||
|
if (string.IsNullOrEmpty(outputPath))
|
||||||
|
{
|
||||||
|
var isTypeScript = codeGenerator.EndsWith(TypeScriptLanguageName, StringComparison.OrdinalIgnoreCase);
|
||||||
|
outputPath = $"{className}{(isTypeScript ? ".ts" : Extension)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place output file in correct directory (relative to project directory).
|
||||||
|
if (!Path.IsPathRooted(outputPath) && !string.IsNullOrEmpty(OutputDirectory))
|
||||||
|
{
|
||||||
|
outputPath = Path.Combine(OutputDirectory, outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!destinations.Add(outputPath))
|
||||||
|
{
|
||||||
|
// This case may occur when user is experimenting e.g. with multiple code generators or options.
|
||||||
|
// May also occur when user accidentally duplicates OutputPath metadata.
|
||||||
|
Log.LogError(Resources.FormatDuplicateFileOutputPaths(outputPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
MetadataSerializer.SetMetadata(newItem, "OutputPath", outputPath);
|
||||||
|
|
||||||
|
// Add metadata which may be used as a property and passed to an inner build.
|
||||||
|
newItem.RemoveMetadata("SerializedMetadata");
|
||||||
|
newItem.SetMetadata("SerializedMetadata", MetadataSerializer.SerializeMetadata(newItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
Outputs = outputs.ToArray();
|
||||||
|
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// 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.IO;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or corrects DocumentPath and project-related metadata in ServiceProjectReference items. Also stores final
|
||||||
|
/// metadata as SerializedMetadata.
|
||||||
|
/// </summary>
|
||||||
|
public class GetProjectReferenceMetadata : Task
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default directory for DocumentPath values.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
var destinations = new HashSet<string>();
|
||||||
|
|
||||||
|
foreach (var item in Inputs)
|
||||||
|
{
|
||||||
|
var newItem = new TaskItem(item);
|
||||||
|
outputs.Add(newItem);
|
||||||
|
|
||||||
|
var documentGenerator = item.GetMetadata("DocumentGenerator");
|
||||||
|
if (string.IsNullOrEmpty(documentGenerator))
|
||||||
|
{
|
||||||
|
// This case occurs when user overrides the default metadata.
|
||||||
|
Log.LogError(Resources.FormatInvalidEmptyMetadataValue(
|
||||||
|
"DocumentGenerator",
|
||||||
|
"ServiceProjectReference",
|
||||||
|
item.ItemSpec));
|
||||||
|
}
|
||||||
|
|
||||||
|
var documentPath = item.GetMetadata("DocumentPath");
|
||||||
|
if (string.IsNullOrEmpty(documentPath))
|
||||||
|
{
|
||||||
|
var filename = item.GetMetadata("Filename");
|
||||||
|
var documentName = item.GetMetadata("DocumentName");
|
||||||
|
if (string.IsNullOrEmpty(documentName))
|
||||||
|
{
|
||||||
|
documentName = "v1";
|
||||||
|
}
|
||||||
|
|
||||||
|
documentPath = $"{filename}.{documentName}.json";
|
||||||
|
}
|
||||||
|
|
||||||
|
documentPath = GetFullPath(documentPath);
|
||||||
|
MetadataSerializer.SetMetadata(newItem, "DocumentPath", documentPath);
|
||||||
|
|
||||||
|
if (!destinations.Add(documentPath))
|
||||||
|
{
|
||||||
|
// This case may occur when user is experimenting e.g. with multiple generators or options.
|
||||||
|
// May also occur when user accidentally duplicates DocumentPath metadata.
|
||||||
|
Log.LogError(Resources.FormatDuplicateProjectDocumentPaths(documentPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add metadata which may be used as a property and passed to an inner build.
|
||||||
|
newItem.SetMetadata("SerializedMetadata", MetadataSerializer.SerializeMetadata(newItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
Outputs = outputs.ToArray();
|
||||||
|
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,128 @@
|
||||||
|
// 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 Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds or corrects DocumentPath metadata in ServiceUriReference items.
|
||||||
|
/// </summary>
|
||||||
|
public class GetUriReferenceMetadata : Task
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default directory for DocumentPath metadata values.
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
var destinations = new HashSet<string>();
|
||||||
|
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);
|
||||||
|
MetadataSerializer.SetMetadata(newItem, "DocumentPath", documentPath);
|
||||||
|
|
||||||
|
if (!destinations.Add(documentPath))
|
||||||
|
{
|
||||||
|
// This case may occur when user is experimenting e.g. with multiple code generators or options.
|
||||||
|
// May also occur when user accidentally duplicates DocumentPath metadata.
|
||||||
|
Log.LogError(Resources.FormatDuplicateUriDocumentPaths(documentPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Outputs = outputs.ToArray();
|
||||||
|
|
||||||
|
return !Log.HasLoggedErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,147 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tasks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Utility methods to serialize and deserialize <see cref="ITaskItem"/> metadata.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Based on and uses the same escaping as
|
||||||
|
/// https://github.com/Microsoft/msbuild/blob/e70a3159d64f9ed6ec3b60253ef863fa883a99b1/src/Shared/EscapingUtilities.cs
|
||||||
|
/// </remarks>
|
||||||
|
public static class MetadataSerializer
|
||||||
|
{
|
||||||
|
private static readonly char[] CharsToEscape = { '%', '*', '?', '@', '$', '(', ')', ';', '\'' };
|
||||||
|
private static readonly HashSet<char> CharsToEscapeHash = new HashSet<char>(CharsToEscape);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add the given <paramref name="key"/> and <paramref name="value"/> to the <paramref name="item"/>. Or,
|
||||||
|
/// modify existing value to be <paramref name="value"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The <see cref="ITaskItem"/> to update.</param>
|
||||||
|
/// <param name="key">The name of the new metadata.</param>
|
||||||
|
/// <param name="value">The value of the new metadata. Assumed to be unescaped.</param>
|
||||||
|
/// <remarks>Uses same hex-encoded format as MSBuild's EscapeUtilities.</remarks>
|
||||||
|
public static void SetMetadata(ITaskItem item, string key, string value)
|
||||||
|
{
|
||||||
|
if (item is ITaskItem2 item2)
|
||||||
|
{
|
||||||
|
item2.SetMetadataValueLiteral(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.IndexOfAny(CharsToEscape) == -1)
|
||||||
|
{
|
||||||
|
item.SetMetadata(key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
EscapeValue(value, builder);
|
||||||
|
item.SetMetadata(key, builder.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serialize metadata for use as a property value passed into an inner build.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to serialize.</param>
|
||||||
|
/// <returns>A <see cref="string"/> containing the serialized metadata.</returns>
|
||||||
|
/// <remarks>Uses same hex-encoded format as MSBuild's EscapeUtilities.</remarks>
|
||||||
|
public static string SerializeMetadata(ITaskItem item)
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
if (item is ITaskItem2 item2)
|
||||||
|
{
|
||||||
|
builder.Append($"Identity={item2.EvaluatedIncludeEscaped}");
|
||||||
|
var metadata = item2.CloneCustomMetadataEscaped();
|
||||||
|
foreach (var key in metadata.Keys)
|
||||||
|
{
|
||||||
|
var value = metadata[key];
|
||||||
|
builder.Append($"|{key.ToString()}={value.ToString()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Append($"Identity=");
|
||||||
|
EscapeValue(item.ItemSpec, builder);
|
||||||
|
|
||||||
|
var metadata = item.CloneCustomMetadata();
|
||||||
|
foreach (var key in metadata.Keys)
|
||||||
|
{
|
||||||
|
builder.Append($"|{key.ToString()}=");
|
||||||
|
|
||||||
|
var value = metadata[key];
|
||||||
|
EscapeValue(value.ToString(), builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Recreate an <see cref="ITaskItem"/> with metadata encoded in given <paramref name="value"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The serialized metadata.</param>
|
||||||
|
/// <returns>The deserialized <see cref="ITaskItem"/>.</returns>
|
||||||
|
public static ITaskItem DeserializeMetadata(string value)
|
||||||
|
{
|
||||||
|
var metadata = value.Split('|');
|
||||||
|
var item = new TaskItem();
|
||||||
|
|
||||||
|
// TaskItem implements ITaskITem2 explicitly and ITaskItem implicitly.
|
||||||
|
var item2 = (ITaskItem2)item;
|
||||||
|
foreach (var segment in metadata)
|
||||||
|
{
|
||||||
|
var keyAndValue = segment.Split(new[] { '=' }, count: 2);
|
||||||
|
if (string.Equals("Identity", keyAndValue[0]))
|
||||||
|
{
|
||||||
|
item2.EvaluatedIncludeEscaped = keyAndValue[1];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
item2.SetMetadata(keyAndValue[0], keyAndValue[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EscapeValue(string value, StringBuilder builder)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
builder.Append(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.IndexOfAny(CharsToEscape) == -1)
|
||||||
|
{
|
||||||
|
builder.Append(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var @char in value)
|
||||||
|
{
|
||||||
|
if (CharsToEscapeHash.Contains(@char))
|
||||||
|
{
|
||||||
|
builder.Append('%');
|
||||||
|
builder.Append(HexDigitChar(@char / 0x10));
|
||||||
|
builder.Append(HexDigitChar(@char & 0x0F));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(@char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char HexDigitChar(int x)
|
||||||
|
{
|
||||||
|
return (char)(x + (x < 10 ? '0' : ('a' - 10)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
<Project Sdk="Internal.AspNetCore.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Execute PopulateNuspec fairly late. -->
|
||||||
|
<GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);PopulateNuspec</GenerateNuspecDependsOn>
|
||||||
|
|
||||||
|
<!-- Do not complain about lack of lib folder. -->
|
||||||
|
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||||
|
|
||||||
|
<AssemblyName>Microsoft.Extensions.ApiDescription.Tasks</AssemblyName>
|
||||||
|
<Description>MSBuild tasks and targets for code generation</Description>
|
||||||
|
<EnableApiCheck>false</EnableApiCheck>
|
||||||
|
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||||
|
<IncludeSource>false</IncludeSource>
|
||||||
|
<IncludeSymbols>false</IncludeSymbols>
|
||||||
|
<NuspecFile>$(MSBuildProjectName).nuspec</NuspecFile>
|
||||||
|
<PackageId>$(MSBuildProjectName)</PackageId>
|
||||||
|
<PackageTags>Build Tasks;MSBuild;Swagger;Open API;code generation; Web API client</PackageTags>
|
||||||
|
<RootNamespace>$(AssemblyName)</RootNamespace>
|
||||||
|
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Build.Utilities.Core"
|
||||||
|
Version="$(MicrosoftBuildUtilitiesCorePackageVersion)" />
|
||||||
|
<PackageReference Include="System.Net.Http"
|
||||||
|
Condition="'$(TargetFramework)' == 'net461'"
|
||||||
|
Version="$(SystemNetHttpPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' != ''">
|
||||||
|
<SignedPackageFile Include="$(TargetPath)">
|
||||||
|
<Certificate>$(AssemblySigningCertName)</Certificate>
|
||||||
|
<PackagePath>tasks/$(TargetFramework)/$(TargetFileName)</PackagePath>
|
||||||
|
<StrongName>$(AssemblySigningStrongName)</StrongName>
|
||||||
|
</SignedPackageFile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Add other signed files in a single inner build, avoiding duplications in this multi-TFM project. -->
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
|
||||||
|
<SignedPackageFile Include="../dotnet-getdocument/bin/$(Configuration)/netcoreapp2.1/publish/dotnet-getdocument.dll">
|
||||||
|
<Certificate>$(AssemblySigningCertName)</Certificate>
|
||||||
|
<PackagePath>tools/dotnet-getdocument.dll</PackagePath>
|
||||||
|
<StrongName>$(AssemblySigningStrongName)</StrongName>
|
||||||
|
</SignedPackageFile>
|
||||||
|
<SignedPackageFile Include="../GetDocumentInsider/bin/$(Configuration)/net461/GetDocument.Insider.exe">
|
||||||
|
<Certificate>$(AssemblySigningCertName)</Certificate>
|
||||||
|
<PackagePath>tools/net461/GetDocument.Insider.exe</PackagePath>
|
||||||
|
<StrongName>$(AssemblySigningStrongName)</StrongName>
|
||||||
|
</SignedPackageFile>
|
||||||
|
<SignedPackageFile Include="../GetDocumentInsider/bin/x86/$(Configuration)/net461/GetDocument.Insider.exe">
|
||||||
|
<Certificate>$(AssemblySigningCertName)</Certificate>
|
||||||
|
<PackagePath>tools/net461-x86/GetDocument.Insider.exe</PackagePath>
|
||||||
|
<StrongName>$(AssemblySigningStrongName)</StrongName>
|
||||||
|
</SignedPackageFile>
|
||||||
|
<SignedPackageFile Include="../GetDocumentInsider/bin/$(Configuration)/netcoreapp2.0/GetDocument.Insider.dll">
|
||||||
|
<Certificate>$(AssemblySigningCertName)</Certificate>
|
||||||
|
<PackagePath>tools/netcoreapp2.0/GetDocument.Insider.exe</PackagePath>
|
||||||
|
<StrongName>$(AssemblySigningStrongName)</StrongName>
|
||||||
|
</SignedPackageFile>
|
||||||
|
|
||||||
|
<SignedPackageFile Include="../dotnet-getdocument/bin/$(Configuration)/netcoreapp2.1/publish/Newtonsoft.Json.dll">
|
||||||
|
<PackagePath>tools/Newtonsoft.Json.dll"</PackagePath>
|
||||||
|
<Certificate>$(AssemblySigning3rdPartyCertName)"</Certificate>
|
||||||
|
</SignedPackageFile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="PopulateNuspec">
|
||||||
|
<MSBuild Projects="../dotnet-getdocument/dotnet-getdocument.csproj"
|
||||||
|
BuildInParallel="$(BuildInParallel)"
|
||||||
|
RemoveProperties="RuntimeIdentifier;TargetFrameworks;TargetFramework"
|
||||||
|
Targets="Publish" />
|
||||||
|
|
||||||
|
<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,30 @@
|
||||||
|
<?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>true</requireLicenseAcceptance>
|
||||||
|
<tags>$tags$</tags>
|
||||||
|
<version>$version$</version>
|
||||||
|
</metadata>
|
||||||
|
|
||||||
|
<files>
|
||||||
|
<file src="build\*" target="build" />
|
||||||
|
<file src="buildMultiTargeting\*" target="buildMultiTargeting" />
|
||||||
|
<file src="bin\$configuration$\net461\Microsoft.Extensions.ApiDescription.Tasks.*" target="tasks\net461" />
|
||||||
|
<file src="bin\$configuration$\netstandard2.0\Microsoft.Extensions.ApiDescription.Tasks.*" target="tasks\netstandard2.0" />
|
||||||
|
<file src="..\dotnet-getdocument\bin\$configuration$\netcoreapp2.1\publish\*.*" target="tools" />
|
||||||
|
<file src="..\GetDocumentInsider\bin\$configuration$\net461\GetDocument.Insider.*" target="tools\net461" />
|
||||||
|
<file src="..\GetDocumentInsider\bin\x86\$configuration$\net461\GetDocument.Insider.*" target="tools\net461-x86" />
|
||||||
|
<file src="..\GetDocumentInsider\bin\$configuration$\netcoreapp2.0\GetDocument.Insider.*" target="tools\netcoreapp2.0" />
|
||||||
|
</files>
|
||||||
|
</package>
|
||||||
86
src/Microsoft.Extensions.ApiDescription.Design/Properties/Resources.Designer.cs
generated
Normal file
86
src/Microsoft.Extensions.ApiDescription.Design/Properties/Resources.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
// <auto-generated />
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tasks
|
||||||
|
{
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
|
||||||
|
internal static class Resources
|
||||||
|
{
|
||||||
|
private static readonly ResourceManager _resourceManager
|
||||||
|
= new ResourceManager("Microsoft.Extensions.ApiDescription.Tasks.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiple items have OutputPath='{0}'. All ServiceFileReference, ServiceProjectReference and ServiceUriReference items must have unique OutputPath metadata.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DuplicateFileOutputPaths
|
||||||
|
{
|
||||||
|
get => GetString("DuplicateFileOutputPaths");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiple items have OutputPath='{0}'. All ServiceFileReference, ServiceProjectReference and ServiceUriReference items must have unique OutputPath metadata.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatDuplicateFileOutputPaths(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("DuplicateFileOutputPaths"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mutliple ServiceProjectReference items have DocumentPath='{0}'. ServiceProjectReference items must have unique DocumentPath metadata.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DuplicateProjectDocumentPaths
|
||||||
|
{
|
||||||
|
get => GetString("DuplicateProjectDocumentPaths");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mutliple ServiceProjectReference items have DocumentPath='{0}'. ServiceProjectReference items must have unique DocumentPath metadata.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatDuplicateProjectDocumentPaths(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("DuplicateProjectDocumentPaths"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mutliple ServiceUriReference items have DocumentPath='{0}'. ServiceUriReference items must have unique DocumentPath metadata.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DuplicateUriDocumentPaths
|
||||||
|
{
|
||||||
|
get => GetString("DuplicateUriDocumentPaths");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mutliple ServiceUriReference items have DocumentPath='{0}'. ServiceUriReference items must have unique DocumentPath metadata.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatDuplicateUriDocumentPaths(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("DuplicateUriDocumentPaths"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invalid {0} metadata value for {1} item '{2}'. {0} metadata must not be set to the empty string.
|
||||||
|
/// </summary>
|
||||||
|
internal static string InvalidEmptyMetadataValue
|
||||||
|
{
|
||||||
|
get => GetString("InvalidEmptyMetadataValue");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invalid {0} metadata value for {1} item '{2}'. {0} metadata must not be set to the empty string.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatInvalidEmptyMetadataValue(object p0, object p1, object p2)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("InvalidEmptyMetadataValue"), p0, p1, p2);
|
||||||
|
|
||||||
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
|
{
|
||||||
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.Assert(value != null);
|
||||||
|
|
||||||
|
if (formatterNames != null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < formatterNames.Length; i++)
|
||||||
|
{
|
||||||
|
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
<?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="DuplicateFileOutputPaths" xml:space="preserve">
|
||||||
|
<value>Multiple items have OutputPath='{0}'. All ServiceFileReference, ServiceProjectReference and ServiceUriReference items must have unique OutputPath metadata.</value>
|
||||||
|
<comment>ServiceProjectReference and ServiceUriReference items become ServiceFileReference items and all ServiceFileReference items must have unique OutputPath metadata.</comment>
|
||||||
|
</data>
|
||||||
|
<data name="DuplicateProjectDocumentPaths" xml:space="preserve">
|
||||||
|
<value>Mutliple ServiceProjectReference items have DocumentPath='{0}'. ServiceProjectReference items must have unique DocumentPath metadata.</value>
|
||||||
|
</data>
|
||||||
|
<data name="DuplicateUriDocumentPaths" xml:space="preserve">
|
||||||
|
<value>Mutliple ServiceUriReference items have DocumentPath='{0}'. ServiceUriReference items must have unique DocumentPath metadata.</value>
|
||||||
|
<comment>Ignore corner case of ServiceProjectReference and ServiceUriReference items having the same DocumentPath.</comment>
|
||||||
|
</data>
|
||||||
|
<data name="InvalidEmptyMetadataValue" xml:space="preserve">
|
||||||
|
<value>Invalid {0} metadata value for {1} item '{2}'. {0} metadata must not be set to the empty string.</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ApiDescriptionTasksAssemblyTarget
|
||||||
|
Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0</_ApiDescriptionTasksAssemblyTarget>
|
||||||
|
<_ApiDescriptionTasksAssemblyTarget
|
||||||
|
Condition="'$(MSBuildRuntimeType)' != 'Core'">net461</_ApiDescriptionTasksAssemblyTarget>
|
||||||
|
<_ApiDescriptionTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_ApiDescriptionTasksAssemblyTarget)/Microsoft.Extensions.ApiDescription.Tasks.dll</_ApiDescriptionTasksAssemblyPath>
|
||||||
|
<_ApiDescriptionTasksAssemblyTarget />
|
||||||
|
</PropertyGroup>
|
||||||
|
<UsingTask TaskName="GetCurrentItems" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
|
||||||
|
<UsingTask TaskName="GetFileReferenceMetadata" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
|
||||||
|
<UsingTask TaskName="GetProjectReferenceMetadata" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
|
||||||
|
<UsingTask TaskName="GetUriReferenceMetadata" AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
|
||||||
|
<UsingTask TaskName="Microsoft.Extensions.ApiDescription.Tasks.DownloadFile"
|
||||||
|
AssemblyFile="$(_ApiDescriptionTasksAssemblyPath)" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Settings users may update as they see fit. All $(...Directory) values are interpreted relative to the client
|
||||||
|
project folder, unless already an absolute path.
|
||||||
|
-->
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<GenerateDefaultDocumentDefaultOptions Condition="'$(GenerateDefaultDocumentDefaultOptions)' == ''" />
|
||||||
|
</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. Builds will invoke a target named
|
||||||
|
"Generate%(DocumentGenerator)Document" to do actual document retrieval / generation.
|
||||||
|
-->
|
||||||
|
<DocumentGenerator>Default</DocumentGenerator>
|
||||||
|
|
||||||
|
<!-- Server project metadata which is likely applicable to all document generators. -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Server project's chosen configuration. Corresponds to $(Configuration) which likely matches client project's
|
||||||
|
$(Configuration).
|
||||||
|
-->
|
||||||
|
<Configuration />
|
||||||
|
<!--
|
||||||
|
Server project's extensions path. Corresponds to $(MSBuildProjectExtensionsPath). User must set this if
|
||||||
|
server project's value is not 'obj/'.
|
||||||
|
-->
|
||||||
|
<ProjectExtensionsPath />
|
||||||
|
<!-- Server project's target framework. Defaults to $(TargetFramework) or first of $(TargetFrameworks). -->
|
||||||
|
<TargetFramework />
|
||||||
|
<!--
|
||||||
|
Full path of the server project's generated assembly. Corresponds to $(TargetPath). Because common code builds
|
||||||
|
server projects, file exists prior to document generator invocation.
|
||||||
|
-->
|
||||||
|
<TargetPath />
|
||||||
|
<!--
|
||||||
|
Semicolon-separated list of targets in the server project that should be built. Default is empty, indicating
|
||||||
|
the default targets of the server project. Does not honor $(ProjectReferenceBuildTargets) because that property
|
||||||
|
is too general for these references and it's normally empty too.
|
||||||
|
-->
|
||||||
|
<Targets />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Metadata specific to the Default document generator (though other document generators are free to use it).
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Options added to Default document generator tool's command line. Defaults to
|
||||||
|
$(GenerateDefaultDocumentDefaultOptions) if that is set in the client project.
|
||||||
|
-->
|
||||||
|
<GenerateDefaultDocumentOptions />
|
||||||
|
<!--
|
||||||
|
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 />
|
||||||
|
</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 $(ServiceUriReferenceDirectory).
|
||||||
|
-->
|
||||||
|
<DocumentPath />
|
||||||
|
</ServiceUriReference>
|
||||||
|
|
||||||
|
<ServiceFileReference>
|
||||||
|
<!-- Name of the class to generate. Defaults to %(Filename)Client but with an uppercase first letter. -->
|
||||||
|
<ClassName />
|
||||||
|
<!--
|
||||||
|
Code generator to use. Required and must end with "CSharp" or "TypeScript" (the currently-supported target
|
||||||
|
languages) unless %(OutputPath) is set. Builds will invoke a target named "Generate%(CodeGenerator)" to do
|
||||||
|
actual code generation.
|
||||||
|
-->
|
||||||
|
<CodeGenerator />
|
||||||
|
<!--
|
||||||
|
Namespace to contain generated class. Default is $(RootNamespace).
|
||||||
|
-->
|
||||||
|
<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
|
||||||
|
$(ServiceFileReferenceDirectory). Final value (depending on $(ServiceFileReferenceDirectory)) is likely to be
|
||||||
|
a path relative to the client project.
|
||||||
|
-->
|
||||||
|
<OutputPath />
|
||||||
|
</ServiceFileReference>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,335 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project>
|
||||||
|
<!-- Internal settings. Not intended for customization. -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<GenerateServiceProjectReferenceDocumentsDependsOn>
|
||||||
|
_GetTargetFrameworkForServiceProjectReferences;
|
||||||
|
_GetTargetPathForServiceProjectReferences;
|
||||||
|
_GetMetadataForServiceProjectReferences;
|
||||||
|
_BuildServiceProjectReferences;
|
||||||
|
_GenerateServiceProjectReferenceDocuments;
|
||||||
|
_CreateFileItemsForServiceProjectReferences
|
||||||
|
</GenerateServiceProjectReferenceDocumentsDependsOn>
|
||||||
|
<GenerateServiceUriReferenceDocumentsDependsOn>
|
||||||
|
_GetMetadataForServiceUriReferences;
|
||||||
|
_GenerateServiceUriReferenceDocuments
|
||||||
|
</GenerateServiceUriReferenceDocumentsDependsOn>
|
||||||
|
<GenerateServiceFileReferenceCodesDependsOn>
|
||||||
|
GenerateServiceProjectReferenceDocuments;
|
||||||
|
GenerateServiceUriReferenceDocuments;
|
||||||
|
_GetMetadataForServiceFileReferences;
|
||||||
|
_GenerateServiceFileReferenceCodes;
|
||||||
|
_CreateCompileItemsForServiceFileReferences
|
||||||
|
</GenerateServiceFileReferenceCodesDependsOn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- ServiceProjectReference support -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Metadata setup phase 1: Ensure items have TargetFramework metadata. Calls GetTargetFrameworks in the target
|
||||||
|
project. Inputs and outputs cause MSBuild to run target unconditionally and to batch it (run once per project).
|
||||||
|
-->
|
||||||
|
<Target Name="_GetTargetFrameworkForServiceProjectReferences"
|
||||||
|
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="'%(TargetFramework)' == ''">$(_TargetFramework)</TargetFramework>
|
||||||
|
</ServiceProjectReference>
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_FullPath />
|
||||||
|
<_TargetFramework />
|
||||||
|
<_TargetFrameworks />
|
||||||
|
</PropertyGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Metadata setup phase 2: Ensure items have TargetPath metadata. Calls 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="_GetTargetPathForServiceProjectReferences"
|
||||||
|
Inputs="%(ServiceProjectReference.TargetFramework)%(FullPath)')"
|
||||||
|
Outputs="<not-a-file !>">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_FullPath>%(ServiceProjectReference.FullPath)</_FullPath>
|
||||||
|
<_TargetFramework>%(ServiceProjectReference.TargetFramework)</_TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<MSBuild Projects="$(_FullPath)"
|
||||||
|
Properties="TargetFramework=$(_TargetFramework)"
|
||||||
|
RebaseOutputs="true"
|
||||||
|
RemoveProperties="TargetFrameworks;RuntimeIdentifier"
|
||||||
|
Targets="GetTargetPath"
|
||||||
|
UseResultsCache="true">
|
||||||
|
<Output TaskParameter="TargetOutputs" ItemName="_Temporary" />
|
||||||
|
</MSBuild>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_TargetPath>%(_Temporary.FullPath)</_TargetPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ServiceProjectReference Update="@(ServiceProjectReference)"
|
||||||
|
Condition="'%(FullPath)' == '$(_FullPath)' AND '%(TargetFramework)' == '$(_TargetFramework)'">
|
||||||
|
<TargetPath>$(_TargetPath)</TargetPath>
|
||||||
|
</ServiceProjectReference>
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<_FullPath />
|
||||||
|
<_TargetPath />
|
||||||
|
<_TargetFramework />
|
||||||
|
</PropertyGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!-- Metadata setup phase 3: Ensure items have DocumentPath metadata. -->
|
||||||
|
<Target Name="_GetMetadataForServiceProjectReferences" Condition="'@(ServiceProjectReference)' != ''">
|
||||||
|
<ItemGroup>
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GetProjectReferenceMetadata Inputs="@(ServiceProjectReference)"
|
||||||
|
DocumentDirectory="$(ServiceProjectReferenceDirectory)">
|
||||||
|
<Output TaskParameter="Outputs" ItemName="_Temporary" />
|
||||||
|
</GetProjectReferenceMetadata>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ServiceProjectReference Remove="@(ServiceProjectReference)" />
|
||||||
|
<ServiceProjectReference Include="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_BuildServiceProjectReferences"
|
||||||
|
Condition="'$(BuildProjectReferences)' == 'true'"
|
||||||
|
Inputs="@(ServiceProjectReference)"
|
||||||
|
Outputs="%(TargetPath)">
|
||||||
|
<MSBuild Projects="@(ServiceProjectReference -> Distinct())"
|
||||||
|
BuildInParallel="$(BuildInParallel)"
|
||||||
|
RemoveProperties="TargetFramework;TargetFrameworks;RuntimeIdentifier"
|
||||||
|
Targets="%(Targets)" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_GetCurrentServiceProjectReference">
|
||||||
|
<GetCurrentItems Input="$(GeneratorMetadata)">
|
||||||
|
<Output TaskParameter="Outputs" ItemName="CurrentServiceProjectReference" />
|
||||||
|
</GetCurrentItems>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_GenerateServiceProjectReferenceDocument"
|
||||||
|
DependsOnTargets="_GetCurrentServiceProjectReference;$(GeneratorTarget)" />
|
||||||
|
|
||||||
|
<Target Name="_GenerateServiceProjectReferenceDocuments"
|
||||||
|
Inputs="@(ServiceProjectReference)"
|
||||||
|
Outputs="%(DocumentPath)">
|
||||||
|
<MSBuild BuildInParallel="$(BuildInParallel)"
|
||||||
|
Projects="$(MSBuildProjectFullPath)"
|
||||||
|
Properties="GeneratorTargetPath=%(ServiceProjectReference.DocumentPath);GeneratorTarget=Generate%(DocumentGenerator)Document;GeneratorMetadata=%(SerializedMetadata)"
|
||||||
|
RemoveProperties="TargetFrameworks"
|
||||||
|
Targets="_GenerateServiceProjectReferenceDocument" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_CreateFileItemsForServiceProjectReferences" Condition="'@(ServiceProjectReference)' != ''">
|
||||||
|
<!-- GetProjectReferenceMetadata task guarantees %(DocumentPath) values are unique. -->
|
||||||
|
<ItemGroup>
|
||||||
|
<ServiceFileReference Remove="@(ServiceProjectReference -> '%(DocumentPath)')" />
|
||||||
|
<!-- Condition here is temporary. Useful while GenerateDefaultDocument fails. -->
|
||||||
|
<ServiceFileReference Include="@(ServiceProjectReference -> '%(DocumentPath)')"
|
||||||
|
Condition="Exists('%(ServiceProjectReference.DocumentPath)')">
|
||||||
|
<SourceProject>%(ServiceProjectReference.FullPath)</SourceProject>
|
||||||
|
</ServiceFileReference>
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="GenerateServiceProjectReferenceDocuments"
|
||||||
|
DependsOnTargets="$(GenerateServiceProjectReferenceDocumentsDependsOn)" />
|
||||||
|
|
||||||
|
<!-- GenerateDefaultDocument -->
|
||||||
|
|
||||||
|
<Target Name="GenerateDefaultDocument">
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- @(CurrentServiceProjectReference) item group will never contain more than one item. -->
|
||||||
|
<CurrentServiceProjectReference Update="@(CurrentServiceProjectReference)">
|
||||||
|
<Command>dotnet $(MSBuildThisFileDirectory)/../tools/dotnet-getdocument.dll --project %(FullPath)</Command>
|
||||||
|
<Configuration Condition="'%(Configuration)' == ''">$(Configuration)</Configuration>
|
||||||
|
<GenerateDefaultDocumentOptions
|
||||||
|
Condition="'%(GenerateDefaultDocumentOptions)' == ''">$(GenerateDefaultDocumentDefaultOptions)</GenerateDefaultDocumentOptions>
|
||||||
|
</CurrentServiceProjectReference>
|
||||||
|
<CurrentServiceProjectReference Update="@(CurrentServiceProjectReference)">
|
||||||
|
<Command>%(Command) --framework %(TargetFramework) --output %(DocumentPath)</Command>
|
||||||
|
</CurrentServiceProjectReference>
|
||||||
|
<CurrentServiceProjectReference Update="@(CurrentServiceProjectReference)">
|
||||||
|
<Command Condition="'%(Method)' != ''">%(Command) --method %(Method)</Command>
|
||||||
|
</CurrentServiceProjectReference>
|
||||||
|
<CurrentServiceProjectReference Update="@(CurrentServiceProjectReference)">
|
||||||
|
<Command Condition="'%(Service)' != ''">%(Command) --service %(Service)</Command>
|
||||||
|
</CurrentServiceProjectReference>
|
||||||
|
<CurrentServiceProjectReference Update="@(CurrentServiceProjectReference)">
|
||||||
|
<Command
|
||||||
|
Condition="'%(ProjectExtensionsPath)' != ''">%(Command) --projectExtensionsPath %(ProjectExtensionsPath)</Command>
|
||||||
|
</CurrentServiceProjectReference>
|
||||||
|
<CurrentServiceProjectReference Update="@(CurrentServiceProjectReference)">
|
||||||
|
<Command>%(Command) --configuration %(Configuration) %(GenerateDefaultDocumentOptions)</Command>
|
||||||
|
</CurrentServiceProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Message Importance="high" Text="%0AGenerateDefaultDocument:" />
|
||||||
|
<Message Importance="high" Text=" %(CurrentServiceProjectReference.Command)" />
|
||||||
|
<Exec Command="%(CurrentServiceProjectReference.Command)"
|
||||||
|
IgnoreExitCode="$([System.IO.File]::Exists('%(DocumentPath)'))" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!-- ServiceUriReference support -->
|
||||||
|
|
||||||
|
<Target Name="_GetMetadataForServiceUriReferences" Condition="'@(ServiceUriReference)' != ''">
|
||||||
|
<ItemGroup>
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GetUriReferenceMetadata Inputs="@(ServiceUriReference)" DocumentDirectory="$(ServiceUriReferenceDirectory)">
|
||||||
|
<Output TaskParameter="Outputs" ItemName="_Temporary" />
|
||||||
|
</GetUriReferenceMetadata>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ServiceUriReference Remove="@(ServiceUriReference)" />
|
||||||
|
<ServiceUriReference Include="@(_Temporary)" />
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_GenerateServiceUriReferenceDocuments" Condition="'@(ServiceUriReference)' != ''">
|
||||||
|
<Microsoft.Extensions.ApiDescription.Tasks.DownloadFile Uri="%(ServiceUriReference.Identity)"
|
||||||
|
DestinationPath="%(DocumentPath)"
|
||||||
|
Overwrite="$(ServiceUriReferenceCheckIfNewer)" />
|
||||||
|
|
||||||
|
<!-- GetUriReferenceMetadata task guarantees %(DocumentPath) values are unique. -->
|
||||||
|
<ItemGroup>
|
||||||
|
<ServiceFileReference Remove="@(ServiceUriReference -> '%(DocumentPath)')" />
|
||||||
|
<ServiceFileReference Include="@(ServiceUriReference -> '%(DocumentPath)')">
|
||||||
|
<SourceUri>%(ServiceUriReference.Identity)</SourceUri>
|
||||||
|
</ServiceFileReference>
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="GenerateServiceUriReferenceDocuments"
|
||||||
|
DependsOnTargets="$(GenerateServiceUriReferenceDocumentsDependsOn)" />
|
||||||
|
|
||||||
|
<!-- ServiceFileReference support -->
|
||||||
|
|
||||||
|
<Target Name="_GetMetadataForServiceFileReferences" Condition="'@(ServiceFileReference)' != ''">
|
||||||
|
<ItemGroup>
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<GetFileReferenceMetadata Inputs="@(ServiceFileReference)"
|
||||||
|
Extension="$(DefaultLanguageSourceExtension)"
|
||||||
|
Namespace="$(RootNamespace)"
|
||||||
|
OutputDirectory="$(ServiceFileReferenceDirectory)">
|
||||||
|
<Output TaskParameter="Outputs" ItemName="_Temporary" />
|
||||||
|
</GetFileReferenceMetadata>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ServiceFileReference Remove="@(ServiceFileReference)" />
|
||||||
|
<ServiceFileReference Include="@(_Temporary)" />
|
||||||
|
<_Temporary Remove="@(_Temporary)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_GetCurrentServiceFileReference">
|
||||||
|
<GetCurrentItems Input="$(GeneratorMetadata)">
|
||||||
|
<Output TaskParameter="Outputs" ItemName="CurrentServiceFileReference" />
|
||||||
|
</GetCurrentItems>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_GenerateServiceFileReferenceCode"
|
||||||
|
DependsOnTargets="_GetCurrentServiceFileReference;$(GeneratorTarget)" />
|
||||||
|
|
||||||
|
<Target Name="_GenerateServiceFileReferenceCodes" Inputs="@(ServiceFileReference)" Outputs="%(OutputPath)">
|
||||||
|
<MSBuild BuildInParallel="$(BuildInParallel)"
|
||||||
|
Projects="$(MSBuildProjectFullPath)"
|
||||||
|
Properties="GeneratorTargetPath=%(ServiceFileReference.OutputPath);GeneratorTarget=Generate%(CodeGenerator);GeneratorMetadata=%(SerializedMetadata)"
|
||||||
|
RemoveProperties="TargetFrameworks"
|
||||||
|
Targets="_GenerateServiceFileReferenceCode" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_CreateCompileItemsForServiceFileReferences" Condition="'@(ServiceFileReference)' != ''">
|
||||||
|
<!--
|
||||||
|
While %(DocumentPath) metadata may include duplicates (due to overlaps between ServiceUriReference and
|
||||||
|
ServiceProjectReference items), GetFileReferenceMetadata task guarantees %(OutputPath) values are unique.
|
||||||
|
-->
|
||||||
|
<ItemGroup>
|
||||||
|
<_Files Remove="@(_Files)" />
|
||||||
|
<_Files Include="@(ServiceFileReference -> '%(OutputPath)')"
|
||||||
|
Condition="$([System.IO.File]::Exists('%(ServiceFileReference.OutputPath)'))">
|
||||||
|
<OutputPathExtension>$([System.IO.Path]::GetExtension('%(ServiceFileReference.OutputPath)'))</OutputPathExtension>
|
||||||
|
</_Files>
|
||||||
|
<_Directories Remove="@(_Directories)" />
|
||||||
|
<_Directories Include="@(ServiceFileReference -> '%(OutputPath)')"
|
||||||
|
Condition="Exists('%(ServiceFileReference.OutputPath)') AND ! $([System.IO.File]::Exists('%(ServiceFileReference.OutputPath)'))" />
|
||||||
|
|
||||||
|
<!-- If OutputPath is a file, add it directly to relevant items. -->
|
||||||
|
<TypeScriptCompile Remove="@(_Files)" Condition="'%(_Files.OutputPathExtension)' == '.ts'" />
|
||||||
|
<TypeScriptCompile Include="@(_Files)" Condition="'%(_Files.OutputPathExtension)' == '.ts'">
|
||||||
|
<SourceDocument>%(_Files.FullPath)</SourceDocument>
|
||||||
|
</TypeScriptCompile>
|
||||||
|
|
||||||
|
<Compile Remove="@(_Files)"
|
||||||
|
Condition="'$(DefaultLanguageSourceExtension)' != '.ts' AND '%(_Files.OutputPathExtension)' == '$(DefaultLanguageSourceExtension)'" />
|
||||||
|
<Compile Include="@(_Files)"
|
||||||
|
Condition="'$(DefaultLanguageSourceExtension)' != '.ts' AND '%(_Files.OutputPathExtension)' == '$(DefaultLanguageSourceExtension)'">
|
||||||
|
<SourceDocument>%(ServiceFileReference.FullPath)</SourceDocument>
|
||||||
|
</Compile>
|
||||||
|
|
||||||
|
<!-- Otherwise, add all descendent files with the expected extension. -->
|
||||||
|
<TypeScriptCompile Remove="@(_Directories -> '%(Identity)/**/*.ts')" />
|
||||||
|
<TypeScriptCompile Include="@(_Directories -> '%(Identity)/**/*.ts')">
|
||||||
|
<SourceDocument>%(_Directories.FullPath)</SourceDocument>
|
||||||
|
</TypeScriptCompile>
|
||||||
|
|
||||||
|
<Compile Remove="@(_Directories -> '%(Identity)/**/*.$(DefaultLanguageSourceExtension)')"
|
||||||
|
Condition="'$(DefaultLanguageSourceExtension)' != '.ts'" />
|
||||||
|
<Compile Include="@(_Directories -> '%(Identity)/**/*.$(DefaultLanguageSourceExtension)')"
|
||||||
|
Condition="'$(DefaultLanguageSourceExtension)' != '.ts'">
|
||||||
|
<SourceDocument>%(_Directories.FullPath)</SourceDocument>
|
||||||
|
</Compile>
|
||||||
|
|
||||||
|
<_Files Remove="@(_Files)" />
|
||||||
|
<_Directories Remove="@(_Directories)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="GenerateServiceFileReferenceCodes"
|
||||||
|
BeforeTargets="BeforeCompile"
|
||||||
|
DependsOnTargets="$(GenerateServiceFileReferenceCodesDependsOn)" />
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
|
<Project>
|
||||||
|
<Target Name="GenerateServiceFileReferenceCodes" BeforeTargets="BeforeCompile">
|
||||||
|
<MsBuild Projects="$(MSBuildProjectFile)"
|
||||||
|
Targets="GenerateServiceFileReferenceCodes"
|
||||||
|
Properties="TargetFramework=$(TargetFrameworks.Split(';')[0])"
|
||||||
|
RemoveProperties="TargetFrameworks;RuntimeIdentifier" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
// 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 Microsoft.DotNet.Cli.CommandLine;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool.Commands
|
||||||
|
{
|
||||||
|
internal class InvokeCommand : HelpCommandBase
|
||||||
|
{
|
||||||
|
private const string InsideManName = "GetDocument.Insider";
|
||||||
|
|
||||||
|
private IList<string> _args;
|
||||||
|
private CommandOption _configuration;
|
||||||
|
private CommandOption _output;
|
||||||
|
private CommandOption _project;
|
||||||
|
private CommandOption _projectExtensionsPath;
|
||||||
|
private CommandOption _runtime;
|
||||||
|
private CommandOption _targetFramework;
|
||||||
|
|
||||||
|
public override void Configure(CommandLineApplication command)
|
||||||
|
{
|
||||||
|
var options = new ProjectOptions();
|
||||||
|
options.Configure(command);
|
||||||
|
|
||||||
|
_configuration = options.Configuration;
|
||||||
|
_project = options.Project;
|
||||||
|
_projectExtensionsPath = options.ProjectExtensionsPath;
|
||||||
|
_runtime = options.Runtime;
|
||||||
|
_targetFramework = options.TargetFramework;
|
||||||
|
|
||||||
|
_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.FormatUsingProject(projectFile));
|
||||||
|
|
||||||
|
var project = Project.FromFile(
|
||||||
|
projectFile,
|
||||||
|
_projectExtensionsPath.Value(),
|
||||||
|
_targetFramework.Value(),
|
||||||
|
_configuration.Value(),
|
||||||
|
_runtime.Value());
|
||||||
|
if (!File.Exists(project.TargetPath))
|
||||||
|
{
|
||||||
|
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.FormatNETCoreApp1Project(project.ProjectName, targetFramework.Version));
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Add("exec");
|
||||||
|
args.Add("--depsFile");
|
||||||
|
args.Add(project.ProjectDepsFilePath);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(project.ProjectAssetsFile))
|
||||||
|
{
|
||||||
|
using (var reader = new JsonTextReader(File.OpenText(project.ProjectAssetsFile)))
|
||||||
|
{
|
||||||
|
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.ProjectRuntimeConfigFilePath))
|
||||||
|
{
|
||||||
|
args.Add("--runtimeConfig");
|
||||||
|
args.Add(project.ProjectRuntimeConfigFilePath);
|
||||||
|
}
|
||||||
|
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.FormatNETStandardProject(project.ProjectName));
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new CommandException(
|
||||||
|
Resources.FormatUnsupportedFramework(project.ProjectName, targetFramework.Identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
args.AddRange(_args);
|
||||||
|
args.Add("--assembly");
|
||||||
|
args.Add(project.TargetPath);
|
||||||
|
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 (_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.ProjectDirectory);
|
||||||
|
}
|
||||||
|
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.FormatNoProjectInDirectory(path)
|
||||||
|
: errorWhenNoProject);
|
||||||
|
}
|
||||||
|
if (projectFiles.Count != 1)
|
||||||
|
{
|
||||||
|
throw new CommandException(
|
||||||
|
specified
|
||||||
|
? Resources.FormatMultipleProjectsInDirectory(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 Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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,42 @@
|
||||||
|
// 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 Microsoft.DotNet.Cli.CommandLine;
|
||||||
|
using Microsoft.Extensions.ApiDescription.Tool.Commands;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
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,235 @@
|
||||||
|
// 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.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using IODirectory = System.IO.Directory;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
internal class Project
|
||||||
|
{
|
||||||
|
private const string ResourceFilename = "ServiceProjectReferenceMetadata.targets";
|
||||||
|
private const string MSBuildResourceName = "Microsoft.Extensions.ApiDescription.Tool." + ResourceFilename;
|
||||||
|
|
||||||
|
private Project()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string AssemblyName { get; private set; }
|
||||||
|
|
||||||
|
public string ConfigPath { get; private set; }
|
||||||
|
|
||||||
|
public string Configuration { get; private set; }
|
||||||
|
|
||||||
|
public string DefaultDocumentName { get; private set; }
|
||||||
|
|
||||||
|
public string DefaultMethod { get; private set; }
|
||||||
|
|
||||||
|
public string DefaultService { get; private set; }
|
||||||
|
|
||||||
|
public string OutputPath { get; private set; }
|
||||||
|
|
||||||
|
public string Platform { get; private set; }
|
||||||
|
|
||||||
|
public string PlatformTarget { get; private set; }
|
||||||
|
|
||||||
|
public string ProjectAssetsFile { get; private set; }
|
||||||
|
|
||||||
|
public string ProjectDepsFilePath { get; private set; }
|
||||||
|
|
||||||
|
public string ProjectDirectory { get; private set; }
|
||||||
|
|
||||||
|
public string ProjectExtensionsPath { get; private set; }
|
||||||
|
|
||||||
|
public string ProjectName { get; private set; }
|
||||||
|
|
||||||
|
public string ProjectRuntimeConfigFilePath { get; private set; }
|
||||||
|
|
||||||
|
public string RuntimeFrameworkVersion { get; private set; }
|
||||||
|
|
||||||
|
public string RuntimeIdentifier { get; private set; }
|
||||||
|
|
||||||
|
public string TargetFramework { get; private set; }
|
||||||
|
|
||||||
|
public string TargetFrameworkMoniker { get; private set; }
|
||||||
|
|
||||||
|
public string TargetPath { get; private set; }
|
||||||
|
|
||||||
|
public static Project FromFile(
|
||||||
|
string projectFile,
|
||||||
|
string buildExtensionsDirectory,
|
||||||
|
string framework = null,
|
||||||
|
string configuration = null,
|
||||||
|
string runtime = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(projectFile))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(buildExtensionsDirectory))
|
||||||
|
{
|
||||||
|
buildExtensionsDirectory = Path.Combine(Path.GetDirectoryName(projectFile), "obj");
|
||||||
|
}
|
||||||
|
|
||||||
|
IODirectory.CreateDirectory(buildExtensionsDirectory);
|
||||||
|
|
||||||
|
var assembly = typeof(Project).Assembly;
|
||||||
|
var targetsPath = Path.Combine(
|
||||||
|
buildExtensionsDirectory,
|
||||||
|
$"{Path.GetFileName(projectFile)}.{ResourceFilename}");
|
||||||
|
using (var input = assembly.GetManifestResourceStream(MSBuildResourceName))
|
||||||
|
{
|
||||||
|
using (var output = File.OpenWrite(targetsPath))
|
||||||
|
{
|
||||||
|
// NB: Copy always in case it changes
|
||||||
|
Reporter.WriteVerbose(Resources.FormatWritingFile(targetsPath));
|
||||||
|
input.CopyTo(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionary<string, string> metadata;
|
||||||
|
var metadataPath = Path.GetTempFileName();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var args = new List<string>
|
||||||
|
{
|
||||||
|
"msbuild",
|
||||||
|
"/target:WriteServiceProjectReferenceMetadata",
|
||||||
|
"/verbosity:quiet",
|
||||||
|
"/nologo",
|
||||||
|
$"/property:ServiceProjectReferenceMetadataPath={metadataPath}",
|
||||||
|
projectFile,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(framework))
|
||||||
|
{
|
||||||
|
args.Add($"/property:TargetFramework={framework}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(configuration))
|
||||||
|
{
|
||||||
|
args.Add($"/property:Configuration={configuration}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(runtime))
|
||||||
|
{
|
||||||
|
args.Add($"/property:RuntimeIdentifier={runtime}");
|
||||||
|
}
|
||||||
|
|
||||||
|
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(metadataPath);
|
||||||
|
File.Delete(targetsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var project = new Project
|
||||||
|
{
|
||||||
|
DefaultDocumentName = metadata[nameof(DefaultDocumentName)],
|
||||||
|
DefaultMethod = metadata[nameof(DefaultMethod)],
|
||||||
|
DefaultService = metadata[nameof(DefaultService)],
|
||||||
|
|
||||||
|
AssemblyName = metadata[nameof(AssemblyName)],
|
||||||
|
Configuration = metadata[nameof(Configuration)],
|
||||||
|
OutputPath = metadata[nameof(OutputPath)],
|
||||||
|
Platform = metadata[nameof(Platform)],
|
||||||
|
PlatformTarget = metadata[nameof(PlatformTarget)] ?? metadata[nameof(Platform)],
|
||||||
|
ProjectAssetsFile = metadata[nameof(ProjectAssetsFile)],
|
||||||
|
ProjectDepsFilePath = metadata[nameof(ProjectDepsFilePath)],
|
||||||
|
ProjectDirectory = metadata[nameof(ProjectDirectory)],
|
||||||
|
ProjectExtensionsPath = metadata[nameof(ProjectExtensionsPath)],
|
||||||
|
ProjectName = metadata[nameof(ProjectName)],
|
||||||
|
ProjectRuntimeConfigFilePath = metadata[nameof(ProjectRuntimeConfigFilePath)],
|
||||||
|
RuntimeFrameworkVersion = metadata[nameof(RuntimeFrameworkVersion)],
|
||||||
|
RuntimeIdentifier = metadata[nameof(RuntimeIdentifier)],
|
||||||
|
TargetFramework = metadata[nameof(TargetFramework)],
|
||||||
|
TargetFrameworkMoniker = metadata[nameof(TargetFrameworkMoniker)],
|
||||||
|
TargetPath = metadata[nameof(TargetPath)],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(project.OutputPath))
|
||||||
|
{
|
||||||
|
throw new CommandException(
|
||||||
|
Resources.FormatGetMetadataValueFailed(nameof(OutputPath), nameof(OutputPath)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(project.ProjectDirectory))
|
||||||
|
{
|
||||||
|
throw new CommandException(
|
||||||
|
Resources.FormatGetMetadataValueFailed(nameof(ProjectDirectory), "MSBuildProjectDirectory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(project.TargetPath))
|
||||||
|
{
|
||||||
|
throw new CommandException(
|
||||||
|
Resources.FormatGetMetadataValueFailed(nameof(TargetPath), nameof(TargetPath)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Path.IsPathRooted(project.ProjectDirectory))
|
||||||
|
{
|
||||||
|
project.OutputPath = Path.GetFullPath(
|
||||||
|
Path.Combine(IODirectory.GetCurrentDirectory(), project.ProjectDirectory));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Path.IsPathRooted(project.OutputPath))
|
||||||
|
{
|
||||||
|
project.OutputPath = Path.GetFullPath(Path.Combine(project.ProjectDirectory, project.OutputPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Path.IsPathRooted(project.ProjectExtensionsPath))
|
||||||
|
{
|
||||||
|
project.ProjectExtensionsPath = Path.GetFullPath(
|
||||||
|
Path.Combine(project.ProjectDirectory, project.ProjectExtensionsPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Path.IsPathRooted(project.TargetPath))
|
||||||
|
{
|
||||||
|
project.TargetPath = Path.GetFullPath(Path.Combine(project.OutputPath, project.TargetPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some document generation tools support non-ASP.NET Core projects. Any of the remaining properties may
|
||||||
|
// thus be null empty.
|
||||||
|
var configPath = $"{project.TargetPath}.config";
|
||||||
|
if (File.Exists(configPath))
|
||||||
|
{
|
||||||
|
project.ConfigPath = configPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(string.IsNullOrEmpty(project.ProjectAssetsFile) || Path.IsPathRooted(project.ProjectAssetsFile)))
|
||||||
|
{
|
||||||
|
project.ProjectAssetsFile = Path.GetFullPath(
|
||||||
|
Path.Combine(project.ProjectDirectory, project.ProjectAssetsFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(string.IsNullOrEmpty(project.ProjectDepsFilePath) || Path.IsPathRooted(project.ProjectDepsFilePath)))
|
||||||
|
{
|
||||||
|
project.ProjectDepsFilePath = Path.GetFullPath(
|
||||||
|
Path.Combine(project.ProjectDirectory, project.ProjectDepsFilePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(string.IsNullOrEmpty(project.ProjectRuntimeConfigFilePath) ||
|
||||||
|
Path.IsPathRooted(project.ProjectRuntimeConfigFilePath)))
|
||||||
|
{
|
||||||
|
project.ProjectRuntimeConfigFilePath = Path.GetFullPath(
|
||||||
|
Path.Combine(project.OutputPath, project.ProjectRuntimeConfigFilePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// 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 Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
internal class ProjectOptions
|
||||||
|
{
|
||||||
|
public CommandOption Configuration { get; private set; }
|
||||||
|
|
||||||
|
public CommandOption Project { get; private set; }
|
||||||
|
|
||||||
|
public CommandOption ProjectExtensionsPath { get; private set; }
|
||||||
|
|
||||||
|
public CommandOption Runtime { get; private set; }
|
||||||
|
|
||||||
|
public CommandOption TargetFramework { get; private set; }
|
||||||
|
|
||||||
|
public void Configure(CommandLineApplication command)
|
||||||
|
{
|
||||||
|
Configuration = command.Option("--configuration <CONFIGURATION>", Resources.ConfigurationDescription);
|
||||||
|
Project = command.Option("-p|--project <PROJECT>", Resources.ProjectDescription);
|
||||||
|
ProjectExtensionsPath = command.Option(
|
||||||
|
"--projectExtensionsPath <PATH>",
|
||||||
|
Resources.ProjectExtensionsPathDescription);
|
||||||
|
Runtime = command.Option("--runtime <RUNTIME_IDENTIFIER>", Resources.RuntimeDescription);
|
||||||
|
TargetFramework = command.Option("--framework <FRAMEWORK>", Resources.TargetFrameworkDescription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,338 @@
|
||||||
|
// <auto-generated />
|
||||||
|
namespace Microsoft.Extensions.ApiDescription.Tool
|
||||||
|
{
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
|
||||||
|
internal static class Resources
|
||||||
|
{
|
||||||
|
private static readonly ResourceManager _resourceManager
|
||||||
|
= new ResourceManager("Microsoft.Extensions.ApiDescription.Tool.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The configuration to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ConfigurationDescription
|
||||||
|
{
|
||||||
|
get => GetString("ConfigurationDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The configuration to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatConfigurationDescription()
|
||||||
|
=> GetString("ConfigurationDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// dotnet-getdocument
|
||||||
|
/// </summary>
|
||||||
|
internal static string CommandFullName
|
||||||
|
{
|
||||||
|
get => GetString("CommandFullName");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// dotnet-getdocument
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatCommandFullName()
|
||||||
|
=> GetString("CommandFullName");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target framework.
|
||||||
|
/// </summary>
|
||||||
|
internal static string TargetFrameworkDescription
|
||||||
|
{
|
||||||
|
get => GetString("TargetFrameworkDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target framework.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatTargetFrameworkDescription()
|
||||||
|
=> GetString("TargetFrameworkDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --projectExtensionsPath option.
|
||||||
|
/// </summary>
|
||||||
|
internal static string GetMetadataFailed
|
||||||
|
{
|
||||||
|
get => GetString("GetMetadataFailed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --projectExtensionsPath option.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatGetMetadataFailed()
|
||||||
|
=> GetString("GetMetadataFailed");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// More than one project was found in the current working directory. Use the --project option.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MultipleProjects
|
||||||
|
{
|
||||||
|
get => GetString("MultipleProjects");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// More than one project was found in the current working directory. Use the --project option.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMultipleProjects()
|
||||||
|
=> GetString("MultipleProjects");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// More than one project was found in directory '{0}'. Specify one using its file name.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MultipleProjectsInDirectory
|
||||||
|
{
|
||||||
|
get => GetString("MultipleProjectsInDirectory");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// More than one project was found in directory '{0}'. Specify one using its file name.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMultipleProjectsInDirectory(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("MultipleProjectsInDirectory"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project '{0}' targets framework '.NETCoreApp' version '{1}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher.
|
||||||
|
/// </summary>
|
||||||
|
internal static string NETCoreApp1Project
|
||||||
|
{
|
||||||
|
get => GetString("NETCoreApp1Project");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project '{0}' targets framework '.NETCoreApp' version '{1}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatNETCoreApp1Project(object p0, object p1)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("NETCoreApp1Project"), p0, p1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project '{0}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the dotnet-getdocument 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>
|
||||||
|
internal static string NETStandardProject
|
||||||
|
{
|
||||||
|
get => GetString("NETStandardProject");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project '{0}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the dotnet-getdocument 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>
|
||||||
|
internal static string FormatNETStandardProject(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("NETStandardProject"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do not colorize output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string NoColorDescription
|
||||||
|
{
|
||||||
|
get => GetString("NoColorDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do not colorize output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatNoColorDescription()
|
||||||
|
=> GetString("NoColorDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No project was found. Change the current working directory or use the --project option.
|
||||||
|
/// </summary>
|
||||||
|
internal static string NoProject
|
||||||
|
{
|
||||||
|
get => GetString("NoProject");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No project was found. Change the current working directory or use the --project option.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatNoProject()
|
||||||
|
=> GetString("NoProject");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No project was found in directory '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string NoProjectInDirectory
|
||||||
|
{
|
||||||
|
get => GetString("NoProjectInDirectory");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No project was found in directory '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatNoProjectInDirectory(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("NoProjectInDirectory"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix output with level.
|
||||||
|
/// </summary>
|
||||||
|
internal static string PrefixDescription
|
||||||
|
{
|
||||||
|
get => GetString("PrefixDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix output with level.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatPrefixDescription()
|
||||||
|
=> GetString("PrefixDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The project to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ProjectDescription
|
||||||
|
{
|
||||||
|
get => GetString("ProjectDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The project to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatProjectDescription()
|
||||||
|
=> GetString("ProjectDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MSBuild project extensions path. Defaults to "obj".
|
||||||
|
/// </summary>
|
||||||
|
internal static string ProjectExtensionsPathDescription
|
||||||
|
{
|
||||||
|
get => GetString("ProjectExtensionsPathDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MSBuild project extensions path. Defaults to "obj".
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatProjectExtensionsPathDescription()
|
||||||
|
=> GetString("ProjectExtensionsPathDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The runtime identifier to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string RuntimeDescription
|
||||||
|
{
|
||||||
|
get => GetString("RuntimeDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The runtime identifier to use.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatRuntimeDescription()
|
||||||
|
=> GetString("RuntimeDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project '{0}' targets framework '{1}'. The dotnet-getdocument tool does not support this framework.
|
||||||
|
/// </summary>
|
||||||
|
internal static string UnsupportedFramework
|
||||||
|
{
|
||||||
|
get => GetString("UnsupportedFramework");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project '{0}' targets framework '{1}'. The dotnet-getdocument tool does not support this framework.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatUnsupportedFramework(object p0, object p1)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("UnsupportedFramework"), p0, p1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using project '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string UsingProject
|
||||||
|
{
|
||||||
|
get => GetString("UsingProject");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using project '{0}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatUsingProject(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("UsingProject"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show verbose output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string VerboseDescription
|
||||||
|
{
|
||||||
|
get => GetString("VerboseDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show verbose output.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatVerboseDescription()
|
||||||
|
=> GetString("VerboseDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writing '{0}'...
|
||||||
|
/// </summary>
|
||||||
|
internal static string WritingFile
|
||||||
|
{
|
||||||
|
get => GetString("WritingFile");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writing '{0}'...
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatWritingFile(object p0)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("WritingFile"), p0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project output not found. Project must be up-to-date when using this tool.
|
||||||
|
/// </summary>
|
||||||
|
internal static string MustBuild
|
||||||
|
{
|
||||||
|
get => GetString("MustBuild");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Project output not found. Project must be up-to-date when using this tool.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatMustBuild()
|
||||||
|
=> GetString("MustBuild");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The file to write the result to.
|
||||||
|
/// </summary>
|
||||||
|
internal static string OutputDescription
|
||||||
|
{
|
||||||
|
get => GetString("OutputDescription");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The file to write the result to.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatOutputDescription()
|
||||||
|
=> GetString("OutputDescription");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unable to retrieve '{0}' project metadata. Ensure '{1}' is set.
|
||||||
|
/// </summary>
|
||||||
|
internal static string GetMetadataValueFailed
|
||||||
|
{
|
||||||
|
get => GetString("GetMetadataValueFailed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unable to retrieve '{0}' project metadata. Ensure '{1}' is set.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatGetMetadataValueFailed(object p0, object p1)
|
||||||
|
=> string.Format(CultureInfo.CurrentCulture, GetString("GetMetadataValueFailed"), p0, p1);
|
||||||
|
|
||||||
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
|
{
|
||||||
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
||||||
|
System.Diagnostics.Debug.Assert(value != null);
|
||||||
|
|
||||||
|
if (formatterNames != null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < formatterNames.Length; i++)
|
||||||
|
{
|
||||||
|
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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="TargetFrameworkDescription" 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 --projectExtensionsPath 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 '{0}'. Specify one using its file name.</value>
|
||||||
|
</data>
|
||||||
|
<data name="NETCoreApp1Project" xml:space="preserve">
|
||||||
|
<value>Project '{0}' targets framework '.NETCoreApp' version '{1}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher.</value>
|
||||||
|
</data>
|
||||||
|
<data name="NETStandardProject" xml:space="preserve">
|
||||||
|
<value>Project '{0}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the dotnet-getdocument 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 '{0}'.</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="ProjectExtensionsPathDescription" 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 '{0}' targets framework '{1}'. The dotnet-getdocument tool does not support this framework.</value>
|
||||||
|
</data>
|
||||||
|
<data name="UsingProject" xml:space="preserve">
|
||||||
|
<value>Using project '{0}'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="VerboseDescription" xml:space="preserve">
|
||||||
|
<value>Show verbose output.</value>
|
||||||
|
</data>
|
||||||
|
<data name="WritingFile" xml:space="preserve">
|
||||||
|
<value>Writing '{0}'...</value>
|
||||||
|
</data>
|
||||||
|
<data name="MustBuild" xml:space="preserve">
|
||||||
|
<value>Project output not found. Project must be up-to-date when using this tool.</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 '{0}' project metadata. Ensure '$({1})' is set.</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?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="WriteServiceProjectReferenceMetadata"
|
||||||
|
Condition="'$(TargetFramework)' != ''"
|
||||||
|
Returns="@(ServiceProjectReferenceMetadata)">
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' != ''">
|
||||||
|
<ServiceProjectReferenceMetadata Include="DefaultDocumentName: $(DefaultServiceProjectDocumentName)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="DefaultMethod: $(DefaultServiceProjectMethod)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="DefaultService: $(DefaultServiceProjectService)" />
|
||||||
|
|
||||||
|
<ServiceProjectReferenceMetadata Include="AssemblyName: $(AssemblyName)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="Configuration: $(Configuration)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="OutputPath: $(OutputPath)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="Platform: $(Platform)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="PlatformTarget: $(PlatformTarget)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="ProjectAssetsFile: $(ProjectAssetsFile)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="ProjectDepsFilePath: $(ProjectDepsFilePath)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="ProjectDirectory: $(MSBuildProjectDirectory)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="ProjectExtensionsPath: $(MSBuildProjectExtensionsPath)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="ProjectName: $(MSBuildProjectName)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="ProjectRuntimeConfigFilePath: $(ProjectRuntimeConfigFilePath)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="RuntimeFrameworkVersion: $(RuntimeFrameworkVersion)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="RuntimeIdentifier: $(RuntimeIdentifier)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="TargetFramework: $(TargetFramework)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="TargetFrameworkMoniker: $(TargetFrameworkMoniker)" />
|
||||||
|
<ServiceProjectReferenceMetadata Include="TargetPath: $(TargetPath)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<!-- Write information only in inner build. -->
|
||||||
|
<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,25 @@
|
||||||
|
<Project Sdk="Internal.AspNetCore.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyName>dotnet-getdocument</AssemblyName>
|
||||||
|
<Description>GetDocument Command-line Tool outside man</Description>
|
||||||
|
<EnableApiCheck>false</EnableApiCheck>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Microsoft.Extensions.ApiDescription.Tool</RootNamespace>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="../GetDocumentInsider/Ansi*.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" />
|
||||||
|
|
||||||
|
<EmbeddedResource Include="ServiceProjectReferenceMetadata.targets" />
|
||||||
|
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
Loading…
Reference in New Issue