From 95b4dc8ca031b2f02775f3d84b374ca222e4d7a8 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Mon, 3 Sep 2018 20:08:00 -0700 Subject: [PATCH 01/14] Add first cut of Microsoft.Extensions.ApiDescription.Client package / project - WIP in a number of ways --- Mvc.NoFun.sln | 45 ++ Mvc.sln | 45 ++ build/dependencies.props | 4 + src/GetDocumentInsider/AnsiConsole.cs | 15 + src/GetDocumentInsider/AnsiConstants.cs | 20 + src/GetDocumentInsider/AnsiTextWriter.cs | 131 ++++ src/GetDocumentInsider/CodeAnnotations.cs | 23 + src/GetDocumentInsider/CommandException.cs | 20 + .../CommandLineUtils/CommandArgument.cs | 19 + .../CommandLineApplication.cs | 604 ++++++++++++++++++ .../CommandLineApplicationExtensions.cs | 18 + .../CommandLineUtils/CommandOption.cs | 125 ++++ .../CommandLineUtils/CommandOptionType.cs | 13 + .../CommandParsingException.cs | 15 + .../Commands/CommandBase.cs | 39 ++ .../Commands/GetDocumentCommand.cs | 175 +++++ .../Commands/GetDocumentCommandContext.cs | 24 + .../Commands/GetDocumentCommandWorker.cs | 260 ++++++++ .../Commands/HelpCommandBase.cs | 17 + .../Commands/ProjectCommandBase.cs | 38 ++ .../GetDocumentInsider.csproj | 39 ++ src/GetDocumentInsider/Json.cs | 19 + src/GetDocumentInsider/LogWrapper.cs | 29 + src/GetDocumentInsider/ProductInfo.cs | 24 + src/GetDocumentInsider/Program.cs | 51 ++ .../Properties/Resources.Designer.cs | 207 ++++++ .../Properties/Resources.Designer.tt | 6 + .../Properties/Resources.resx | 192 ++++++ src/GetDocumentInsider/Reporter.cs | 58 ++ src/GetDocumentInsider/WrappedException.cs | 24 + .../DownloadFile.cs | 113 ++++ .../DownloadFileCore.cs | 118 ++++ .../GetFileReferenceMetadata.cs | 95 +++ .../GetProjectReferenceMetadata.cs | 76 +++ .../GetUriReferenceMetadata.cs | 118 ++++ .../ILogWrapper.cs | 50 ++ .../LogWrapper.cs | 35 + ...ft.Extensions.ApiDescription.Client.csproj | 46 ++ ...ft.Extensions.ApiDescription.Client.nuspec | 28 + .../ServiceProjectReferenceMetadata.targets | 32 + .../build/GenerationTasks.props | 133 ++++ .../build/GenerationTasks.targets | 234 +++++++ .../build/NSwagServiceReference.props | 20 + .../build/NSwagServiceReference.targets | 131 ++++ .../GenerationTasks.targets | 29 + .../Commands/InvokeCommand.cs | 241 +++++++ src/dotnet-getdocument/Exe.cs | 118 ++++ src/dotnet-getdocument/Program.cs | 43 ++ src/dotnet-getdocument/Project.cs | 228 +++++++ src/dotnet-getdocument/ProjectOptions.cs | 30 + .../Properties/Resources.Designer.cs | 179 ++++++ .../Properties/Resources.Designer.tt | 6 + .../Properties/Resources.resx | 186 ++++++ .../ServiceProjectReferenceMetadata.props | 17 + .../ServiceProjectReferenceMetadata.targets | 49 ++ .../dotnet-getdocument.csproj | 112 ++++ .../dotnet-getdocument.nuspec | 28 + 57 files changed, 4794 insertions(+) create mode 100644 src/GetDocumentInsider/AnsiConsole.cs create mode 100644 src/GetDocumentInsider/AnsiConstants.cs create mode 100644 src/GetDocumentInsider/AnsiTextWriter.cs create mode 100644 src/GetDocumentInsider/CodeAnnotations.cs create mode 100644 src/GetDocumentInsider/CommandException.cs create mode 100644 src/GetDocumentInsider/CommandLineUtils/CommandArgument.cs create mode 100644 src/GetDocumentInsider/CommandLineUtils/CommandLineApplication.cs create mode 100644 src/GetDocumentInsider/CommandLineUtils/CommandLineApplicationExtensions.cs create mode 100644 src/GetDocumentInsider/CommandLineUtils/CommandOption.cs create mode 100644 src/GetDocumentInsider/CommandLineUtils/CommandOptionType.cs create mode 100644 src/GetDocumentInsider/CommandLineUtils/CommandParsingException.cs create mode 100644 src/GetDocumentInsider/Commands/CommandBase.cs create mode 100644 src/GetDocumentInsider/Commands/GetDocumentCommand.cs create mode 100644 src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs create mode 100644 src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs create mode 100644 src/GetDocumentInsider/Commands/HelpCommandBase.cs create mode 100644 src/GetDocumentInsider/Commands/ProjectCommandBase.cs create mode 100644 src/GetDocumentInsider/GetDocumentInsider.csproj create mode 100644 src/GetDocumentInsider/Json.cs create mode 100644 src/GetDocumentInsider/LogWrapper.cs create mode 100644 src/GetDocumentInsider/ProductInfo.cs create mode 100644 src/GetDocumentInsider/Program.cs create mode 100644 src/GetDocumentInsider/Properties/Resources.Designer.cs create mode 100644 src/GetDocumentInsider/Properties/Resources.Designer.tt create mode 100644 src/GetDocumentInsider/Properties/Resources.resx create mode 100644 src/GetDocumentInsider/Reporter.cs create mode 100644 src/GetDocumentInsider/WrappedException.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets create mode 100644 src/dotnet-getdocument/Commands/InvokeCommand.cs create mode 100644 src/dotnet-getdocument/Exe.cs create mode 100644 src/dotnet-getdocument/Program.cs create mode 100644 src/dotnet-getdocument/Project.cs create mode 100644 src/dotnet-getdocument/ProjectOptions.cs create mode 100644 src/dotnet-getdocument/Properties/Resources.Designer.cs create mode 100644 src/dotnet-getdocument/Properties/Resources.Designer.tt create mode 100644 src/dotnet-getdocument/Properties/Resources.resx create mode 100644 src/dotnet-getdocument/ServiceProjectReferenceMetadata.props create mode 100644 src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets create mode 100644 src/dotnet-getdocument/dotnet-getdocument.csproj create mode 100644 src/dotnet-getdocument/dotnet-getdocument.nuspec diff --git a/Mvc.NoFun.sln b/Mvc.NoFun.sln index 3995a5463a..0167992a7f 100644 --- a/Mvc.NoFun.sln +++ b/Mvc.NoFun.sln @@ -117,6 +117,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ap EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.Api.Analyzers.Test", "test\Mvc.Api.Analyzers.Test\Mvc.Api.Analyzers.Test.csproj", "{71C626FC-6408-494B-A127-38CB64F71324}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\dotnet-getdocument\dotnet-getdocument.csproj", "{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client", "src\Microsoft.Extensions.ApiDescription.Client\Microsoft.Extensions.ApiDescription.Client.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -575,6 +581,42 @@ Global {71C626FC-6408-494B-A127-38CB64F71324}.Release|Mixed Platforms.Build.0 = Release|Any CPU {71C626FC-6408-494B-A127-38CB64F71324}.Release|x86.ActiveCfg = Release|Any CPU {71C626FC-6408-494B-A127-38CB64F71324}.Release|x86.Build.0 = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.ActiveCfg = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.Build.0 = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.Build.0 = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.ActiveCfg = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.Build.0 = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.ActiveCfg = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.Build.0 = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.Build.0 = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.ActiveCfg = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.Build.0 = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.ActiveCfg = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.Build.0 = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.Build.0 = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.ActiveCfg = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -619,6 +661,9 @@ Global {92D959F2-66B8-490A-BA33-DA4421EBC948} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {1B398182-9EAE-400B-A2BD-EFFAC0168A36} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {71C626FC-6408-494B-A127-38CB64F71324} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {2F683CF8-B055-46AE-BF83-9D1307F8D45F} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {34E3C302-B767-40C8-B538-3EE2BD4000C4} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D003597F-372F-4068-A2F0-353BE3C3B39A} diff --git a/Mvc.sln b/Mvc.sln index 775683a5fa..ce10a95245 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -178,6 +178,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ap EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorRendering", "benchmarkapps\RazorRendering\RazorRendering.csproj", "{D7C6A696-F232-4288-BCCD-367407E4A934}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\dotnet-getdocument\dotnet-getdocument.csproj", "{4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client", "src\Microsoft.Extensions.ApiDescription.Client\Microsoft.Extensions.ApiDescription.Client.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -938,6 +944,42 @@ Global {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|Mixed Platforms.Build.0 = Release|Any CPU {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.ActiveCfg = Release|Any CPU {D7C6A696-F232-4288-BCCD-367407E4A934}.Release|x86.Build.0 = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.ActiveCfg = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Debug|x86.Build.0 = Debug|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Any CPU.Build.0 = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.ActiveCfg = Release|Any CPU + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6}.Release|x86.Build.0 = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.ActiveCfg = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Debug|x86.Build.0 = Debug|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Any CPU.Build.0 = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.ActiveCfg = Release|Any CPU + {2F683CF8-B055-46AE-BF83-9D1307F8D45F}.Release|x86.Build.0 = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.ActiveCfg = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Debug|x86.Build.0 = Debug|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Any CPU.Build.0 = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.ActiveCfg = Release|Any CPU + {34E3C302-B767-40C8-B538-3EE2BD4000C4}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1010,6 +1052,9 @@ Global {DD7B9F20-354C-4D9E-8C8A-8AE6E7595A87} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} {3B550487-10E4-4E6D-9CEF-B1B4CA1253DA} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {D7C6A696-F232-4288-BCCD-367407E4A934} = {2859F266-673A-45A2-9E3C-7B39C6DDD38E} + {4EDC489F-3EC5-4AE3-9841-A285F40F5FF6} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {2F683CF8-B055-46AE-BF83-9D1307F8D45F} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {34E3C302-B767-40C8-B538-3EE2BD4000C4} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {63D344F6-F86D-40E6-85B9-0AABBE338C4A} diff --git a/build/dependencies.props b/build/dependencies.props index 4e7f5dcd1f..304c16413f 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -54,9 +54,11 @@ 2.2.0-preview3-35359 2.2.0-preview3-35359 2.2.0-preview3-35359 + 2.0.0 2.2.0-preview3-35359 2.2.0-preview3-35359 5.2.6 + 15.6.82 2.8.0 2.8.0 2.2.0-preview3-35359 @@ -100,8 +102,10 @@ 4.7.49 2.0.3 1.0.1 + 11.0.2 4.5.0 4.5.0 + 4.3.2 4.5.1 0.10.0 2.3.1 diff --git a/src/GetDocumentInsider/AnsiConsole.cs b/src/GetDocumentInsider/AnsiConsole.cs new file mode 100644 index 0000000000..30397229aa --- /dev/null +++ b/src/GetDocumentInsider/AnsiConsole.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace GetDocument +{ + internal class AnsiConsole + { + public static readonly AnsiTextWriter _out = new AnsiTextWriter(Console.Out); + + public static void WriteLine(string text) + => _out.WriteLine(text); + } +} diff --git a/src/GetDocumentInsider/AnsiConstants.cs b/src/GetDocumentInsider/AnsiConstants.cs new file mode 100644 index 0000000000..e529180983 --- /dev/null +++ b/src/GetDocumentInsider/AnsiConstants.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace GetDocument +{ + internal static class AnsiConstants + { + public const string Reset = "\x1b[22m\x1b[39m"; + public const string Bold = "\x1b[1m"; + public const string Dark = "\x1b[22m"; + public const string Black = "\x1b[30m"; + public const string Red = "\x1b[31m"; + public const string Green = "\x1b[32m"; + public const string Yellow = "\x1b[33m"; + public const string Blue = "\x1b[34m"; + public const string Magenta = "\x1b[35m"; + public const string Cyan = "\x1b[36m"; + public const string Gray = "\x1b[37m"; + } +} diff --git a/src/GetDocumentInsider/AnsiTextWriter.cs b/src/GetDocumentInsider/AnsiTextWriter.cs new file mode 100644 index 0000000000..c8393d4810 --- /dev/null +++ b/src/GetDocumentInsider/AnsiTextWriter.cs @@ -0,0 +1,131 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; + +namespace GetDocument +{ + internal class AnsiTextWriter + { + private readonly TextWriter _writer; + + public AnsiTextWriter(TextWriter writer) => _writer = writer; + + public void WriteLine(string text) + { + Interpret(text); + _writer.Write(Environment.NewLine); + } + + private void Interpret(string value) + { + var matches = Regex.Matches(value, "\x1b\\[([0-9]+)?m"); + + var start = 0; + foreach (Match match in matches) + { + var length = match.Index - start; + if (length != 0) + { + _writer.Write(value.Substring(start, length)); + } + + Apply(match.Groups[1].Value); + + start = match.Index + match.Length; + } + + if (start != value.Length) + { + _writer.Write(value.Substring(start)); + } + } + + private static void Apply(string parameter) + { + switch (parameter) + { + case "1": + ApplyBold(); + break; + + case "22": + ResetBold(); + break; + + case "30": + ApplyColor(ConsoleColor.Black); + break; + + case "31": + ApplyColor(ConsoleColor.DarkRed); + break; + + case "32": + ApplyColor(ConsoleColor.DarkGreen); + break; + + case "33": + ApplyColor(ConsoleColor.DarkYellow); + break; + + case "34": + ApplyColor(ConsoleColor.DarkBlue); + break; + + case "35": + ApplyColor(ConsoleColor.DarkMagenta); + break; + + case "36": + ApplyColor(ConsoleColor.DarkCyan); + break; + + case "37": + ApplyColor(ConsoleColor.Gray); + break; + + case "39": + ResetColor(); + break; + + default: + Debug.Fail("Unsupported parameter: " + parameter); + break; + } + } + + private static void ApplyBold() + => Console.ForegroundColor = (ConsoleColor)((int)Console.ForegroundColor | 8); + + private static void ResetBold() + => Console.ForegroundColor = (ConsoleColor)((int)Console.ForegroundColor & 7); + + private static void ApplyColor(ConsoleColor color) + { + var wasBold = ((int)Console.ForegroundColor & 8) != 0; + + Console.ForegroundColor = color; + + if (wasBold) + { + ApplyBold(); + } + } + + private static void ResetColor() + { + var wasBold = ((int)Console.ForegroundColor & 8) != 0; + + Console.ResetColor(); + + if (wasBold) + { + ApplyBold(); + } + } + } +} diff --git a/src/GetDocumentInsider/CodeAnnotations.cs b/src/GetDocumentInsider/CodeAnnotations.cs new file mode 100644 index 0000000000..7a179f24d3 --- /dev/null +++ b/src/GetDocumentInsider/CodeAnnotations.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field)] + internal sealed class NotNullAttribute : Attribute + { + } + + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field)] + internal sealed class CanBeNullAttribute : Attribute + { + } +} diff --git a/src/GetDocumentInsider/CommandException.cs b/src/GetDocumentInsider/CommandException.cs new file mode 100644 index 0000000000..5d9778e61f --- /dev/null +++ b/src/GetDocumentInsider/CommandException.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace GetDocument +{ + internal class CommandException : Exception + { + public CommandException(string message) + : base(message) + { + } + + public CommandException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/GetDocumentInsider/CommandLineUtils/CommandArgument.cs b/src/GetDocumentInsider/CommandLineUtils/CommandArgument.cs new file mode 100644 index 0000000000..3346ea0ecb --- /dev/null +++ b/src/GetDocumentInsider/CommandLineUtils/CommandArgument.cs @@ -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(); + + public string Name { get; set; } + public string Description { get; set; } + public List Values { get; private set; } + public bool MultipleValues { get; set; } + public string Value => Values.FirstOrDefault(); + } +} diff --git a/src/GetDocumentInsider/CommandLineUtils/CommandLineApplication.cs b/src/GetDocumentInsider/CommandLineUtils/CommandLineApplication.cs new file mode 100644 index 0000000000..facbb68ad0 --- /dev/null +++ b/src/GetDocumentInsider/CommandLineUtils/CommandLineApplication.cs @@ -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(); + Arguments = new List(); + Commands = new List(); + RemainingArguments = new List(); + 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 Options { get; private set; } + public CommandOption OptionHelp { get; private set; } + public CommandOption OptionVersion { get; private set; } + public List Arguments { get; private set; } + public List RemainingArguments { get; private set; } + public bool IsShowingInformation { get; protected set; } // Is showing help or version? + public Func Invoke { get; set; } + public Func LongVersionGetter { get; set; } + public Func ShortVersionGetter { get; set; } + public List 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 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 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 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 invoke) => Invoke = invoke; + + public void OnExecute(Func> invoke) => Invoke = () => invoke().Result; + + public int Execute(params string[] args) + { + var command = this; + IEnumerator 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 shortFormVersionGetter, + Func 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(" [[--] ...]]"); + } + 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 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 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 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 ExpandResponseFiles(IEnumerable 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 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 + { + private readonly IEnumerator _enumerator; + + public CommandArgumentEnumerator(IEnumerator 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(); + } + } +} diff --git a/src/GetDocumentInsider/CommandLineUtils/CommandLineApplicationExtensions.cs b/src/GetDocumentInsider/CommandLineUtils/CommandLineApplicationExtensions.cs new file mode 100644 index 0000000000..1c43455ee1 --- /dev/null +++ b/src/GetDocumentInsider/CommandLineUtils/CommandLineApplicationExtensions.cs @@ -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); + } +} diff --git a/src/GetDocumentInsider/CommandLineUtils/CommandOption.cs b/src/GetDocumentInsider/CommandLineUtils/CommandOption.cs new file mode 100644 index 0000000000..5ba4b78ae3 --- /dev/null +++ b/src/GetDocumentInsider/CommandLineUtils/CommandOption.cs @@ -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(); + + 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 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'); + } +} diff --git a/src/GetDocumentInsider/CommandLineUtils/CommandOptionType.cs b/src/GetDocumentInsider/CommandLineUtils/CommandOptionType.cs new file mode 100644 index 0000000000..5f7d37f029 --- /dev/null +++ b/src/GetDocumentInsider/CommandLineUtils/CommandOptionType.cs @@ -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 + } +} diff --git a/src/GetDocumentInsider/CommandLineUtils/CommandParsingException.cs b/src/GetDocumentInsider/CommandLineUtils/CommandParsingException.cs new file mode 100644 index 0000000000..c735ecbf12 --- /dev/null +++ b/src/GetDocumentInsider/CommandLineUtils/CommandParsingException.cs @@ -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; } + } +} diff --git a/src/GetDocumentInsider/Commands/CommandBase.cs b/src/GetDocumentInsider/Commands/CommandBase.cs new file mode 100644 index 0000000000..4f66e51d5e --- /dev/null +++ b/src/GetDocumentInsider/Commands/CommandBase.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using GetDocument.Properties; +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument.Commands +{ + internal abstract class CommandBase + { + public virtual void Configure(CommandLineApplication command) + { + var verbose = command.Option("-v|--verbose", Resources.VerboseDescription); + var noColor = command.Option("--no-color", Resources.NoColorDescription); + var prefixOutput = command.Option("--prefix-output", Resources.PrefixDescription); + + command.HandleResponseFiles = true; + + command.OnExecute( + () => + { + Reporter.IsVerbose = verbose.HasValue(); + Reporter.NoColor = noColor.HasValue(); + Reporter.PrefixOutput = prefixOutput.HasValue(); + + Validate(); + + return Execute(); + }); + } + + protected virtual void Validate() + { + } + + protected virtual int Execute() + => 0; + } +} diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs new file mode 100644 index 0000000000..f615e4399b --- /dev/null +++ b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs @@ -0,0 +1,175 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Reflection; +#if NETCOREAPP2_0 +using System.Runtime.Loader; +#endif +using GetDocument.Properties; +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument.Commands +{ + internal class GetDocumentCommand : ProjectCommandBase + { + internal const string FallbackDocumentName = "v1"; + internal const string FallbackMethod = "Generate"; + internal const string FallbackService = "Microsoft.Extensions.ApiDescription.IDocumentProvider"; + private const string WorkerType = "GetDocument.Commands.GetDocumentCommandWorker"; + + private CommandOption _documentName; + private CommandOption _method; + private CommandOption _output; + private CommandOption _service; + private CommandOption _uri; + + public override void Configure(CommandLineApplication command) + { + base.Configure(command); + + _documentName = command.Option( + "--documentName ", + Resources.DocumentDescription(FallbackDocumentName)); + _method = command.Option("--method ", Resources.MethodDescription(FallbackMethod)); + _output = command.Option("--output ", Resources.OutputDescription); + _service = command.Option("--service ", Resources.ServiceDescription(FallbackService)); + _uri = command.Option("--uri ", Resources.UriDescription); + } + + protected override void Validate() + { + base.Validate(); + + if (!_output.HasValue()) + { + throw new CommandException(Resources.MissingOption(_output.LongName)); + } + + if (_method.HasValue() && !_service.HasValue()) + { + throw new CommandException(Resources.MissingOption(_service.LongName)); + } + + if (_service.HasValue() && !_method.HasValue()) + { + throw new CommandException(Resources.MissingOption(_method.LongName)); + } + } + + protected override int Execute() + { + var thisAssembly = typeof(GetDocumentCommand).Assembly; + + var toolsDirectory = ToolsDirectory.Value(); + var packagedAssemblies = Directory + .EnumerateFiles(toolsDirectory, "*.dll") + .Except(new[] { Path.GetFullPath(thisAssembly.Location) }) + .ToDictionary(path => Path.GetFileNameWithoutExtension(path), path => new AssemblyInfo(path)); + + // Explicitly load all assemblies we need first to preserve target project as much as possible. This + // executable is always run in the target project's context (either through location or .deps.json file). + foreach (var keyValuePair in packagedAssemblies) + { + try + { + keyValuePair.Value.Assembly = Assembly.Load(new AssemblyName(keyValuePair.Key)); + } + catch + { + // Ignore all failures because missing assemblies should be loadable from tools directory. + } + } + +#if NETCOREAPP2_0 + AssemblyLoadContext.Default.Resolving += (loadContext, assemblyName) => + { + var name = assemblyName.Name; + if (!packagedAssemblies.TryGetValue(name, out var info)) + { + return null; + } + + var assemblyPath = info.Path; + if (!File.Exists(assemblyPath)) + { + throw new InvalidOperationException( + $"Referenced assembly '{name}' was not found in '{toolsDirectory}'."); + } + + return loadContext.LoadFromAssemblyPath(assemblyPath); + }; + +#elif NET461 + AppDomain.CurrentDomain.AssemblyResolve += (source, eventArgs) => + { + var assemblyName = new AssemblyName(eventArgs.Name); + var name = assemblyName.Name; + if (!packagedAssemblies.TryGetValue(name, out var info)) + { + return null; + } + + var assembly = info.Assembly; + if (assembly != null) + { + // Loaded already + return assembly; + } + + var assemblyPath = info.Path; + if (!File.Exists(assemblyPath)) + { + throw new InvalidOperationException( + $"Referenced assembly '{name}' was not found in '{toolsDirectory}'."); + } + + return Assembly.LoadFile(assemblyPath); + }; +#else +#error target frameworks need to be updated. +#endif + + // Now safe to reference TestHost type. + try + { + var workerType = thisAssembly.GetType(WorkerType, throwOnError: true); + var methodInfo = workerType.GetMethod("Process", BindingFlags.Public | BindingFlags.Static); + + var assemblyPath = AssemblyPath.Value(); + var context = new GetDocumentCommandContext + { + AssemblyPath = assemblyPath, + AssemblyDirectory = Path.GetDirectoryName(assemblyPath), + AssemblyName = Path.GetFileNameWithoutExtension(assemblyPath), + DocumentName = _documentName.Value(), + Method = _method.Value(), + Output = _output.Value(), + Service = _service.Value(), + Uri = _uri.Value(), + }; + + return (int)methodInfo.Invoke(obj: null, parameters: new[] { context }); + } + catch (Exception ex) + { + Console.Error.WriteLine(ex.ToString()); + return 1; + } + } + + private class AssemblyInfo + { + public AssemblyInfo(string path) + { + Path = path; + } + + public string Path { get; } + + public Assembly Assembly { get; set; } + } + } +} diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs new file mode 100644 index 0000000000..996e9e9701 --- /dev/null +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs @@ -0,0 +1,24 @@ +using System; + +namespace GetDocument.Commands +{ + [Serializable] + public class GetDocumentCommandContext + { + public string AssemblyDirectory { get; set; } + + public string AssemblyName { get; set; } + + public string AssemblyPath { get; set; } + + public string DocumentName { get; set; } + + public string Method { get; set; } + + public string Output { get; set; } + + public string Service { get; set; } + + public string Uri { get; set; } + } +} diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs new file mode 100644 index 0000000000..c010165e61 --- /dev/null +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs @@ -0,0 +1,260 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using GenerationTasks; +using GetDocument.Properties; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace GetDocument.Commands +{ + internal class GetDocumentCommandWorker + { + public static int Process(GetDocumentCommandContext context) + { + var assemblyName = new AssemblyName(context.AssemblyName); + var assembly = Assembly.Load(assemblyName); + var entryPointType = assembly.EntryPoint?.DeclaringType; + if (entryPointType == null) + { + Reporter.WriteError(Resources.MissingEntryPoint(context.AssemblyPath)); + return 2; + } + + var services = GetServices(entryPointType, context.AssemblyPath, context.AssemblyName); + if (services == null) + { + return 3; + } + + var success = TryProcess(context, services); + if (!success && string.IsNullOrEmpty(context.Uri)) + { + return 4; + } + + var builder = GetBuilder(entryPointType, context.AssemblyPath, context.AssemblyName); + if (builder == null) + { + return 5; + } + + // Mute the HttpsRedirectionMiddleware warning about HTTPS configuration. + builder.ConfigureLogging(loggingBuilder => loggingBuilder.AddFilter( + "Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware", + LogLevel.Error)); + + using (var server = new TestServer(builder)) + { + ProcessAsync(context, server).Wait(); + } + + return 0; + } + + public static bool TryProcess(GetDocumentCommandContext context, IServiceProvider services) + { + var documentName = string.IsNullOrEmpty(context.DocumentName) ? + GetDocumentCommand.FallbackDocumentName : + context.DocumentName; + var methodName = string.IsNullOrEmpty(context.Method) ? + GetDocumentCommand.FallbackMethod : + context.Method; + var serviceName = string.IsNullOrEmpty(context.Service) ? + GetDocumentCommand.FallbackService : + context.Service; + + Reporter.WriteInformation(Resources.UsingDocument(documentName)); + Reporter.WriteInformation(Resources.UsingMethod(methodName)); + Reporter.WriteInformation(Resources.UsingService(serviceName)); + + try + { + var serviceType = Type.GetType(serviceName, throwOnError: true); + var method = serviceType.GetMethod(methodName, new[] { typeof(TextWriter), typeof(string) }); + var service = services.GetRequiredService(serviceType); + + var success = true; + using (var writer = File.CreateText(context.Output)) + { + if (method.ReturnType == typeof(bool)) + { + success = (bool)method.Invoke(service, new object[] { writer, documentName }); + } + else + { + method.Invoke(service, new object[] { writer, documentName }); + } + } + + if (!success) + { + var message = Resources.MethodInvocationFailed(methodName, serviceName, documentName); + if (string.IsNullOrEmpty(context.Uri) && !File.Exists(context.Output)) + { + Reporter.WriteError(message); + } + else + { + Reporter.WriteWarning(message); + } + } + + return success; + } + catch (Exception ex) + { + var message = FormatException(ex); + if (string.IsNullOrEmpty(context.Uri) && !File.Exists(context.Output)) + { + Reporter.WriteError(message); + } + else + { + Reporter.WriteWarning(message); + } + + return false; + } + } + + public static async Task ProcessAsync(GetDocumentCommandContext context, TestServer server) + { + + Debug.Assert(!string.IsNullOrEmpty(context.Uri)); + Reporter.WriteInformation(Resources.UsingUri(context.Uri)); + + var httpClient = server.CreateClient(); + await DownloadFileCore.DownloadAsync( + context.Uri, + context.Output, + httpClient, + new LogWrapper(), + CancellationToken.None, + timeoutSeconds: 60); + } + + // TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available. + private static IServiceProvider GetServices(Type entryPointType, string assemblyPath, string assemblyName) + { + var args = new[] { Array.Empty() }; + var methodInfo = entryPointType.GetMethod("BuildWebHost"); + if (methodInfo != null) + { + // BuildWebHost (old style has highest priority) + var parameters = methodInfo.GetParameters(); + if (!methodInfo.IsStatic || + parameters.Length != 1 || + typeof(string[]) != parameters[0].ParameterType || + typeof(IWebHost) != methodInfo.ReturnType) + { + Reporter.WriteError( + "BuildWebHost method found in {assemblyPath} does not have expected signature."); + + return null; + } + + try + { + var webHost = (IWebHost)methodInfo.Invoke(obj: null, parameters: args); + + return webHost.Services; + } + catch (Exception ex) + { + Reporter.WriteError($"BuildWebHost method threw: {FormatException(ex)}"); + + return null; + } + } + + if ((methodInfo = entryPointType.GetMethod("CreateWebHostBuilder")) != null) + { + // CreateWebHostBuilder + var parameters = methodInfo.GetParameters(); + if (!methodInfo.IsStatic || + parameters.Length != 1 || + typeof(string[]) != parameters[0].ParameterType || + typeof(IWebHostBuilder) != methodInfo.ReturnType) + { + Reporter.WriteError( + "CreateWebHostBuilder method found in {assemblyPath} does not have expected signature."); + + return null; + } + + try + { + var builder = (IWebHostBuilder)methodInfo.Invoke(obj: null, parameters: args); + + return builder.Build().Services; + } + catch (Exception ex) + { + Reporter.WriteError($"CreateWebHostBuilder method threw: {FormatException(ex)}"); + + return null; + } + } + + // Startup + return new WebHostBuilder().UseStartup(assemblyName).Build().Services; + } + + // TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available. + private static IWebHostBuilder GetBuilder(Type entryPointType, string assemblyPath, string assemblyName) + { + var methodInfo = entryPointType.GetMethod("BuildWebHost"); + if (methodInfo != null) + { + // BuildWebHost cannot be used. Fall through, most likely to Startup fallback. + Reporter.WriteWarning( + "BuildWebHost method cannot be used. Falling back to minimal Startup configuration."); + } + + methodInfo = entryPointType.GetMethod("CreateWebHostBuilder"); + if (methodInfo != null) + { + // CreateWebHostBuilder + var parameters = methodInfo.GetParameters(); + if (!methodInfo.IsStatic || + parameters.Length != 1 || + typeof(string[]) != parameters[0].ParameterType || + typeof(IWebHostBuilder) != methodInfo.ReturnType) + { + Reporter.WriteError( + "CreateWebHostBuilder method found in {assemblyPath} does not have expected signature."); + + return null; + } + + try + { + var args = new[] { Array.Empty() }; + var builder = (IWebHostBuilder)methodInfo.Invoke(obj: null, parameters: args); + + return builder; + } + catch (Exception ex) + { + Reporter.WriteError($"CreateWebHostBuilder method threw: {FormatException(ex)}"); + + return null; + } + } + + // Startup + return new WebHostBuilder().UseStartup(assemblyName); + } + + private static string FormatException(Exception exception) + { + return $"{exception.GetType().FullName}: {exception.Message}"; + } + } +} diff --git a/src/GetDocumentInsider/Commands/HelpCommandBase.cs b/src/GetDocumentInsider/Commands/HelpCommandBase.cs new file mode 100644 index 0000000000..7e2c89cb5a --- /dev/null +++ b/src/GetDocumentInsider/Commands/HelpCommandBase.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument.Commands +{ + internal class HelpCommandBase : CommandBase + { + public override void Configure(CommandLineApplication command) + { + base.Configure(command); + + command.HelpOption("-h|--help"); + } + } +} diff --git a/src/GetDocumentInsider/Commands/ProjectCommandBase.cs b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs new file mode 100644 index 0000000000..a1a762f96c --- /dev/null +++ b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs @@ -0,0 +1,38 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using GetDocument.Properties; +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument.Commands +{ + internal abstract class ProjectCommandBase : HelpCommandBase + { + public CommandOption AssemblyPath { get; private set; } + + public CommandOption ToolsDirectory { get; private set; } + + public override void Configure(CommandLineApplication command) + { + base.Configure(command); + + AssemblyPath = command.Option("-a|--assembly ", Resources.AssemblyDescription); + ToolsDirectory = command.Option("--tools-directory ", Resources.ToolsDirectoryDescription); + } + + protected override void Validate() + { + base.Validate(); + + if (!AssemblyPath.HasValue()) + { + throw new CommandException(Resources.MissingOption(AssemblyPath.LongName)); + } + + if (!ToolsDirectory.HasValue()) + { + throw new CommandException(Resources.MissingOption(ToolsDirectory.LongName)); + } + } + } +} diff --git a/src/GetDocumentInsider/GetDocumentInsider.csproj b/src/GetDocumentInsider/GetDocumentInsider.csproj new file mode 100644 index 0000000000..8fe28cd313 --- /dev/null +++ b/src/GetDocumentInsider/GetDocumentInsider.csproj @@ -0,0 +1,39 @@ + + + GetDocument.Insider + GetDocument Command-line Tool inside man + false + Exe + GetDocument + netcoreapp2.0;net461 + + + + + + + + + + + + + + + TextTemplatingFileGenerator + Resources.Designer.cs + + + + + + + + + + True + True + Resources.Designer.tt + + + diff --git a/src/GetDocumentInsider/Json.cs b/src/GetDocumentInsider/Json.cs new file mode 100644 index 0000000000..acb62e449f --- /dev/null +++ b/src/GetDocumentInsider/Json.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using GetDocument.Properties; +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument +{ + internal static class Json + { + public static CommandOption ConfigureOption(CommandLineApplication command) + => command.Option("--json", Resources.JsonDescription); + + public static string Literal(string text) + => text != null + ? "\"" + text.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"" + : "null"; + } +} diff --git a/src/GetDocumentInsider/LogWrapper.cs b/src/GetDocumentInsider/LogWrapper.cs new file mode 100644 index 0000000000..0ab10cb744 --- /dev/null +++ b/src/GetDocumentInsider/LogWrapper.cs @@ -0,0 +1,29 @@ +using System; +using GenerationTasks; + +namespace GetDocument +{ + public class LogWrapper : ILogWrapper + { + public void LogError(string message, params object[] messageArgs) + { + Reporter.WriteError(string.Format(message, messageArgs)); + } + + public void LogError(Exception exception, bool showStackTrace) + { + var message = showStackTrace ? exception.ToString() : exception.Message; + Reporter.WriteError(message); + } + + public void LogInformational(string message, params object[] messageArgs) + { + Reporter.WriteInformation(string.Format(message, messageArgs)); + } + + public void LogWarning(string message, params object[] messageArgs) + { + Reporter.WriteWarning(string.Format(message, messageArgs)); + } + } +} diff --git a/src/GetDocumentInsider/ProductInfo.cs b/src/GetDocumentInsider/ProductInfo.cs new file mode 100644 index 0000000000..22045ee0df --- /dev/null +++ b/src/GetDocumentInsider/ProductInfo.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; + +namespace GetDocument +{ + /// + /// This API supports the GetDocument infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public static class ProductInfo + { + /// + /// This API supports the GetDocument infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public static string GetVersion() + => typeof(ProductInfo) + .Assembly + .GetCustomAttribute() + .InformationalVersion; + } +} diff --git a/src/GetDocumentInsider/Program.cs b/src/GetDocumentInsider/Program.cs new file mode 100644 index 0000000000..935fca4de0 --- /dev/null +++ b/src/GetDocumentInsider/Program.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Text; +using GetDocument.Commands; +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument +{ + internal static class Program + { + private static int Main(string[] args) + { + if (Console.IsOutputRedirected) + { + Console.OutputEncoding = Encoding.UTF8; + } + + var app = new CommandLineApplication(throwOnUnexpectedArg: false) + { + Name = "GetDocument.Insider" + }; + + new GetDocumentCommand().Configure(app); + + try + { + return app.Execute(args); + } + catch (Exception ex) + { + if (ex is CommandException + || ex is CommandParsingException + || (ex is WrappedException wrappedException + && wrappedException.Type == "GetDocument.Design.OperationException")) + { + Reporter.WriteVerbose(ex.ToString()); + } + else + { + Reporter.WriteInformation(ex.ToString()); + } + + Reporter.WriteError(ex.Message); + + return 1; + } + } + } +} diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.cs b/src/GetDocumentInsider/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..90463782ab --- /dev/null +++ b/src/GetDocumentInsider/Properties/Resources.Designer.cs @@ -0,0 +1,207 @@ +// + +using System; +using System.Reflection; +using System.Resources; +using JetBrains.Annotations; + +namespace GetDocument.Properties +{ + /// + /// This API supports the GetDocument infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("GetDocument.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// The assembly to use. + /// + public static string AssemblyDescription + => GetString("AssemblyDescription"); + + /// + /// Show JSON output. + /// + public static string JsonDescription + => GetString("JsonDescription"); + + /// + /// Missing required option '--{option}'. + /// + public static string MissingOption([CanBeNull] object option) + => string.Format( + GetString("MissingOption", nameof(option)), + option); + + /// + /// Do not colorize output. + /// + public static string NoColorDescription + => GetString("NoColorDescription"); + + /// + /// The file to write the result to. + /// + public static string OutputDescription + => GetString("OutputDescription"); + + /// + /// Prefix console output with logging level. + /// + public static string PrefixDescription + => GetString("PrefixDescription"); + + /// + /// Using application base '{appBase}'. + /// + public static string UsingApplicationBase([CanBeNull] object appBase) + => string.Format( + GetString("UsingApplicationBase", nameof(appBase)), + appBase); + + /// + /// Using assembly '{assembly}'. + /// + public static string UsingAssembly([CanBeNull] object assembly) + => string.Format( + GetString("UsingAssembly", nameof(assembly)), + assembly); + + /// + /// Using configuration file '{config}'. + /// + public static string UsingConfigurationFile([CanBeNull] object config) + => string.Format( + GetString("UsingConfigurationFile", nameof(config)), + config); + + /// + /// Show verbose output. + /// + public static string VerboseDescription + => GetString("VerboseDescription"); + + /// + /// Writing '{file}'... + /// + public static string WritingFile([CanBeNull] object file) + => string.Format( + GetString("WritingFile", nameof(file)), + file); + + /// + /// Using working directory '{workingDirectory}'. + /// + public static string UsingWorkingDirectory([CanBeNull] object workingDirectory) + => string.Format( + GetString("UsingWorkingDirectory", nameof(workingDirectory)), + workingDirectory); + + /// + /// Location from which inside man was copied (in the .NET Framework case) or loaded. + /// + public static string ToolsDirectoryDescription + => GetString("ToolsDirectoryDescription"); + + /// + /// The URI to download the document from. + /// + public static string UriDescription + => GetString("UriDescription"); + + /// + /// The name of the method to invoke on the '--service' instance. Default value '{defaultMethod}'. + /// + public static string MethodDescription([CanBeNull] object defaultMethod) + => string.Format( + GetString("MethodDescription", nameof(defaultMethod)), + defaultMethod); + + /// + /// The qualified name of the service type to retrieve from dependency injection. Default value '{defaultService}'. + /// + public static string ServiceDescription([CanBeNull] object defaultService) + => string.Format( + GetString("ServiceDescription", nameof(defaultService)), + defaultService); + + /// + /// Missing required option '--{option1}' or '--{option2}'. + /// + public static string MissingOptions([CanBeNull] object option1, [CanBeNull] object option2) + => string.Format( + GetString("MissingOptions", nameof(option1), nameof(option2)), + option1, option2); + + /// + /// The name of the document to pass to the '--method' method. Default value '{defaultDocumentName}'. + /// + public static string DocumentDescription([CanBeNull] object defaultDocumentName) + => string.Format( + GetString("DocumentDescription", nameof(defaultDocumentName)), + defaultDocumentName); + + /// + /// Using document name '{documentName}'. + /// + public static string UsingDocument([CanBeNull] object documentName) + => string.Format( + GetString("UsingDocument", nameof(documentName)), + documentName); + + /// + /// Using method '{method}'. + /// + public static string UsingMethod([CanBeNull] object method) + => string.Format( + GetString("UsingMethod", nameof(method)), + method); + + /// + /// Using service '{service}'. + /// + public static string UsingService([CanBeNull] object service) + => string.Format( + GetString("UsingService", nameof(service)), + service); + + /// + /// Using URI '{uri}'. + /// + public static string UsingUri([CanBeNull] object uri) + => string.Format( + GetString("UsingUri", nameof(uri)), + uri); + + /// + /// Method '{method}' of service '{service}' failed to generate document '{documentName}'. + /// + public static string MethodInvocationFailed([CanBeNull] object method, [CanBeNull] object service, [CanBeNull] object documentName) + => string.Format( + GetString("MethodInvocationFailed", nameof(method), nameof(service), nameof(documentName)), + method, service, documentName); + + /// + /// Assembly '{assemblyPath}' does not contain an entry point. + /// + public static string MissingEntryPoint([CanBeNull] object assemblyPath) + => string.Format( + GetString("MissingEntryPoint", nameof(assemblyPath)), + assemblyPath); + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + + return value; + } + } +} + diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.tt b/src/GetDocumentInsider/Properties/Resources.Designer.tt new file mode 100644 index 0000000000..3f636a4db5 --- /dev/null +++ b/src/GetDocumentInsider/Properties/Resources.Designer.tt @@ -0,0 +1,6 @@ +<# + Session["ResourceFile"] = "Resources.resx"; + Session["AccessModifier"] = "internal"; + Session["NoDiagnostics"] = true; +#> +<#@ include file="..\..\tools\Resources.tt" #> diff --git a/src/GetDocumentInsider/Properties/Resources.resx b/src/GetDocumentInsider/Properties/Resources.resx new file mode 100644 index 0000000000..f5c08e3a40 --- /dev/null +++ b/src/GetDocumentInsider/Properties/Resources.resx @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The assembly to use. + + + Show JSON output. + + + Missing required option '--{option}'. + + + Do not colorize output. + + + The file to write the result to. + + + Prefix console output with logging level. + + + Using application base '{appBase}'. + + + Using assembly '{assembly}'. + + + Using configuration file '{config}'. + + + Show verbose output. + + + Writing '{file}'... + + + Using working directory '{workingDirectory}'. + + + Location from which inside man was copied (in the .NET Framework case) or loaded. + + + The URI to download the document from. + + + The name of the method to invoke on the '--service' instance. Default value '{defaultMethod}'. + + + The qualified name of the service type to retrieve from dependency injection. Default value '{defaultService}'. + + + Missing required option '--{option1}' or '--{option2}'. + + + The name of the document to pass to the '--method' method. Default value '{defaultDocumentName}'. + + + Using document name '{documentName}'. + + + Using method '{method}'. + + + Using service '{service}'. + + + Using URI '{uri}'. + + + Method '{method}' of service '{service}' failed to generate document '{documentName}'. + + + Assembly '{assemblyPath}' does not contain an entry point. + + \ No newline at end of file diff --git a/src/GetDocumentInsider/Reporter.cs b/src/GetDocumentInsider/Reporter.cs new file mode 100644 index 0000000000..b7c0c264a5 --- /dev/null +++ b/src/GetDocumentInsider/Reporter.cs @@ -0,0 +1,58 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using static GetDocument.AnsiConstants; + +namespace GetDocument +{ + internal static class Reporter + { + public static bool IsVerbose { get; set; } + public static bool NoColor { get; set; } + public static bool PrefixOutput { get; set; } + + public static string Colorize(string value, Func 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); + } + } + } +} diff --git a/src/GetDocumentInsider/WrappedException.cs b/src/GetDocumentInsider/WrappedException.cs new file mode 100644 index 0000000000..7cd7bfc0d3 --- /dev/null +++ b/src/GetDocumentInsider/WrappedException.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace GetDocument +{ + internal class WrappedException : Exception + { + private readonly string _stackTrace; + + public WrappedException(string type, string message, string stackTrace) + : base(message) + { + Type = type; + _stackTrace = stackTrace; + } + + public string Type { get; } + + public override string ToString() + => _stackTrace; + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs new file mode 100644 index 0000000000..a1341e0581 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs @@ -0,0 +1,113 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Task = System.Threading.Tasks.Task; +using Utilities = Microsoft.Build.Utilities; + +namespace GenerationTasks +{ + /// + /// Downloads a file. + /// + public class DownloadFile : Utilities.Task, ICancelableTask + { + private readonly CancellationTokenSource _cts = new CancellationTokenSource(); + + /// + /// The URI to download. + /// + [Required] + public string Uri { get; set; } + + /// + /// Destination for the downloaded file. If the file already exists, it is not re-downloaded unless + /// is true. + /// + [Required] + public string DestinationPath { get; set; } + + /// + /// Should be overwritten. When true, the file is downloaded and its hash + /// compared to the existing file. If those hashes do not match (or does not + /// exist), is overwritten. + /// + public bool Overwrite { get; set; } + + /// + /// The maximum amount of time in seconds to allow for downloading the file. Defaults to 2 minutes. + /// + public int TimeoutSeconds { get; set; } = 60 * 2; + + /// + public void Cancel() => _cts.Cancel(); + + /// + public override bool Execute() => ExecuteAsync().Result; + + public async Task ExecuteAsync() + { + if (string.IsNullOrEmpty(Uri)) + { + Log.LogError("Uri parameter must not be null or empty."); + return false; + } + + if (string.IsNullOrEmpty(Uri)) + { + Log.LogError("DestinationPath parameter must not be null or empty."); + return false; + } + + var builder = new UriBuilder(Uri); + if (!string.Equals(System.Uri.UriSchemeHttp, builder.Scheme, StringComparison.OrdinalIgnoreCase) && + !string.Equals(System.Uri.UriSchemeHttps, builder.Scheme, StringComparison.OrdinalIgnoreCase)) + { + Log.LogError($"{nameof(Uri)} parameter does not have scheme {System.Uri.UriSchemeHttp} or " + + $"{System.Uri.UriSchemeHttps}."); + return false; + } + + await DownloadFileAsync(Uri, DestinationPath, Overwrite, _cts.Token, TimeoutSeconds, Log); + + return !Log.HasLoggedErrors; + } + + private static async Task DownloadFileAsync( + string uri, + string destinationPath, + bool overwrite, + CancellationToken cancellationToken, + int timeoutSeconds, + TaskLoggingHelper log) + { + var destinationExists = File.Exists(destinationPath); + if (destinationExists && !overwrite) + { + log.LogMessage($"Not downloading '{uri}' to overwrite existing file '{destinationPath}'."); + return; + } + + log.LogMessage($"Downloading '{uri}' to '{destinationPath}'."); + + using (var httpClient = new HttpClient + { + }) + { + await DownloadFileCore.DownloadAsync( + uri, + destinationPath, + httpClient, + new LogWrapper(log), + cancellationToken, + timeoutSeconds); + } + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs new file mode 100644 index 0000000000..bf8156e32f --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs @@ -0,0 +1,118 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; + +namespace GenerationTasks +{ + internal static class DownloadFileCore + { + public static async Task DownloadAsync( + string uri, + string destinationPath, + HttpClient httpClient, + ILogWrapper log, + CancellationToken cancellationToken, + int timeoutSeconds) + { + // Timeout if the response has not begun within 1 minute + httpClient.Timeout = TimeSpan.FromMinutes(1); + + var destinationExists = File.Exists(destinationPath); + var reachedCopy = false; + try + { + using (var response = await httpClient.GetAsync(uri, cancellationToken)) + { + response.EnsureSuccessStatusCode(); + cancellationToken.ThrowIfCancellationRequested(); + + using (var responseStreamTask = response.Content.ReadAsStreamAsync()) + { + var finished = await Task.WhenAny( + responseStreamTask, + Task.Delay(TimeSpan.FromSeconds(timeoutSeconds))); + + if (!ReferenceEquals(responseStreamTask, finished)) + { + throw new TimeoutException($"Download failed to complete in {timeoutSeconds} seconds."); + } + + var responseStream = await responseStreamTask; + if (destinationExists) + { + // Check hashes before using the downloaded information. + var downloadHash = GetHash(responseStream); + responseStream.Position = 0L; + + byte[] destinationHash; + using (var destinationStream = File.OpenRead(destinationPath)) + { + destinationHash = GetHash(destinationStream); + } + + var sameHashes = downloadHash.LongLength == destinationHash.LongLength; + for (var i = 0L; sameHashes && i < downloadHash.LongLength; i++) + { + sameHashes = downloadHash[i] == destinationHash[i]; + } + + if (sameHashes) + { + log.LogInformational($"Not overwriting existing and matching file '{destinationPath}'."); + return; + } + } + else + { + // May need to create directory to hold the file. + var destinationDirectory = Path.GetDirectoryName(destinationPath); + if (!(string.IsNullOrEmpty(destinationDirectory) || Directory.Exists(destinationDirectory))) + { + Directory.CreateDirectory(destinationDirectory); + } + } + + // Create or overwrite the destination file. + reachedCopy = true; + using (var outStream = File.Create(destinationPath)) + { + responseStream.CopyTo(outStream); + } + } + } + } + catch (HttpRequestException ex) when (destinationExists) + { + if (ex.InnerException is SocketException socketException) + { + log.LogWarning($"Unable to download {uri}, socket error code '{socketException.SocketErrorCode}'."); + } + else + { + log.LogWarning($"Unable to download {uri}: {ex.Message}"); + } + } + catch (Exception ex) + { + log.LogError($"Downloading '{uri}' failed."); + log.LogError(ex, showStackTrace: true); + if (reachedCopy) + { + File.Delete(destinationPath); + } + } + } + + private static byte[] GetHash(Stream stream) + { + using (var algorithm = SHA256.Create()) + { + return algorithm.ComputeHash(stream); + } + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs new file mode 100644 index 0000000000..6ae50f8b21 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace GenerationTasks +{ + /// + /// Adds or corrects Namespace and OutputPath metadata in ServiceFileReference items. + /// + public class GetFileReferenceMetadata : Task + { + /// + /// Default Namespace metadata value for C# output. + /// + [Required] + public string CSharpNamespace { get; set; } + + /// + /// Default directory for OutputPath values. + /// + [Required] + public string OutputDirectory { get; set; } + + /// + /// Default Namespace metadata value for TypeScript output. + /// + [Required] + public string TypeScriptNamespace { get; set; } + + /// + /// The ServiceFileReference items to update. + /// + [Required] + public ITaskItem[] Inputs { get; set; } + + /// + /// The updated ServiceFileReference items. Will include Namespace and OutputPath metadata. OutputPath metadata + /// will contain full paths. + /// + [Output] + public ITaskItem[] Outputs{ get; set; } + + /// + public override bool Execute() + { + var outputs = new List(Inputs.Length); + foreach (var item in Inputs) + { + var newItem = new TaskItem(item); + outputs.Add(newItem); + + var codeGenerator = item.GetMetadata("CodeGenerator"); + var isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase); + + var @namespace = item.GetMetadata("Namespace"); + if (string.IsNullOrEmpty(@namespace)) + { + @namespace = isTypeScript ? CSharpNamespace : TypeScriptNamespace; + newItem.SetMetadata("Namespace", @namespace); + } + + var outputPath = item.GetMetadata("OutputPath"); + if (string.IsNullOrEmpty(outputPath)) + { + var className = item.GetMetadata("ClassName"); + outputPath = className + (isTypeScript ? ".ts" : ".cs"); + } + + outputPath = GetFullPath(outputPath); + newItem.SetMetadata("OutputPath", outputPath); + } + + Outputs = outputs.ToArray(); + + return true; + } + + private string GetFullPath(string path) + { + if (!Path.IsPathRooted(path)) + { + if (!string.IsNullOrEmpty(OutputDirectory)) + { + path = Path.Combine(OutputDirectory, path); + } + + path = Path.GetFullPath(path); + } + + return path; + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs new file mode 100644 index 0000000000..e8ac95a819 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace GenerationTasks +{ + /// + /// Adds or corrects DocumentPath and project-related metadata in ServiceProjectReference items. + /// + public class GetProjectReferenceMetadata : Task + { + /// + /// Default directory for DocumentPath values. + /// + [Required] + public string DocumentDirectory { get; set; } + + /// + /// The ServiceFileReference items to update. + /// + [Required] + public ITaskItem[] Inputs { get; set; } + + /// + /// The updated ServiceFileReference items. Will include Namespace and OutputPath metadata. OutputPath metadata + /// will contain full paths. + /// + [Output] + public ITaskItem[] Outputs{ get; set; } + + /// + public override bool Execute() + { + var outputs = new List(Inputs.Length); + foreach (var item in Inputs) + { + var newItem = new TaskItem(item); + outputs.Add(newItem); + + var codeGenerator = item.GetMetadata("CodeGenerator"); + var isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase); + + var outputPath = item.GetMetadata("OutputPath"); + if (string.IsNullOrEmpty(outputPath)) + { + var className = item.GetMetadata("ClassName"); + outputPath = className + (isTypeScript ? ".ts" : ".cs"); + } + + outputPath = GetFullPath(outputPath); + newItem.SetMetadata("OutputPath", outputPath); + } + + Outputs = outputs.ToArray(); + + return true; + } + + private string GetFullPath(string path) + { + if (!Path.IsPathRooted(path)) + { + if (!string.IsNullOrEmpty(DocumentDirectory)) + { + path = Path.Combine(DocumentDirectory, path); + } + + path = Path.GetFullPath(path); + } + + return path; + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs new file mode 100644 index 0000000000..7d922e19dc --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace GenerationTasks +{ + /// + /// Adds or corrects DocumentPath metadata in ServiceUriReference items. + /// + public class GetUriReferenceMetadata : Task + { + /// + /// Default directory for DocumentPath metadata values. + /// + [Required] + public string DocumentDirectory { get; set; } + + /// + /// The ServiceUriReference items to update. + /// + [Required] + public ITaskItem[] Inputs { get; set; } + + /// + /// The updated ServiceUriReference items. Will include DocumentPath metadata with full paths. + /// + [Output] + public ITaskItem[] Outputs{ get; set; } + + /// + public override bool Execute() + { + var outputs = new List(Inputs.Length); + foreach (var item in Inputs) + { + var newItem = new TaskItem(item); + outputs.Add(newItem); + + var documentPath = item.GetMetadata("DocumentPath"); + if (string.IsNullOrEmpty(documentPath)) + { + var uri = item.ItemSpec; + var builder = new UriBuilder(uri); + if (!builder.Uri.IsAbsoluteUri) + { + Log.LogError($"{nameof(Inputs)} item '{uri}' is not an absolute URI."); + return false; + } + + if (!string.Equals(Uri.UriSchemeHttp, builder.Scheme, StringComparison.OrdinalIgnoreCase) && + !string.Equals(Uri.UriSchemeHttps, builder.Scheme, StringComparison.OrdinalIgnoreCase)) + { + Log.LogError($"{nameof(Inputs)} item '{uri}' does not have scheme {Uri.UriSchemeHttp} or " + + $"{Uri.UriSchemeHttps}."); + return false; + } + + var host = builder.Host + .Replace("/", string.Empty) + .Replace("[", string.Empty) + .Replace("]", string.Empty) + .Replace(':', '_'); + var path = builder.Path + .Replace("!", string.Empty) + .Replace("'", string.Empty) + .Replace("$", string.Empty) + .Replace("%", string.Empty) + .Replace("&", string.Empty) + .Replace("(", string.Empty) + .Replace(")", string.Empty) + .Replace("*", string.Empty) + .Replace("@", string.Empty) + .Replace("~", string.Empty) + .Replace('/', '_') + .Replace(':', '_') + .Replace(';', '_') + .Replace('+', '_') + .Replace('=', '_'); + + documentPath = host + path; + if (char.IsLower(documentPath[0])) + { + documentPath = char.ToUpper(documentPath[0]) + documentPath.Substring(startIndex: 1); + } + + if (!documentPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) + { + documentPath = $"{documentPath}.json"; + } + } + + documentPath = GetFullPath(documentPath); + newItem.SetMetadata("DocumentPath", documentPath); + } + + Outputs = outputs.ToArray(); + + return true; + } + + private string GetFullPath(string path) + { + if (!Path.IsPathRooted(path)) + { + if (!string.IsNullOrEmpty(DocumentDirectory)) + { + path = Path.Combine(DocumentDirectory, path); + } + + path = Path.GetFullPath(path); + } + + return path; + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs b/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs new file mode 100644 index 0000000000..7c773ab359 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs @@ -0,0 +1,50 @@ +using System; + +namespace GenerationTasks +{ + internal interface ILogWrapper + { + /// + /// Logs specified informational . Implementations should be thread safe. + /// + /// The message to log. + /// Optional arguments for formatting the string. + /// + /// Thrown when is . + /// + void LogInformational(string message, params object[] messageArgs); + + /// + /// Logs a warning with the specified . Implementations should be thread safe. + /// + /// The message to log. + /// Optional arguments for formatting the string. + /// + /// Thrown when is . + /// + void LogWarning(string message, params object[] messageArgs); + + /// + /// Logs an error with the specified . Implementations should be thread safe. + /// + /// The message to log. + /// Optional arguments for formatting the string. + /// + /// Thrown when is . + /// + void LogError(string message, params object[] messageArgs); + + /// + /// Logs an error with the message and (optionally) the stack trace of the given . + /// Implementations should be thread safe. + /// + /// The to log. + /// + /// If , append stack trace to 's message. + /// + /// + /// Thrown when is . + /// + void LogError(Exception exception, bool showStackTrace); + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs b/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs new file mode 100644 index 0000000000..75ae1407a8 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.Build.Utilities; + +namespace GenerationTasks +{ + internal class LogWrapper : ILogWrapper + { + private readonly TaskLoggingHelper _log; + + public LogWrapper(TaskLoggingHelper log) + { + _log = log; + } + + public void LogError(string message, params object[] messageArgs) + { + _log.LogError(message, messageArgs); + } + + public void LogError(Exception exception, bool showStackTrace) + { + _log.LogErrorFromException(exception, showStackTrace); + } + + public void LogInformational(string message, params object[] messageArgs) + { + _log.LogMessage(message, messageArgs); + } + + public void LogWarning(string message, params object[] messageArgs) + { + _log.LogWarning(message, messageArgs); + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj new file mode 100644 index 0000000000..5dab6ea1aa --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj @@ -0,0 +1,46 @@ + + + + $(GenerateNuspecDependsOn);PopulateNuspec + + + true + + MSBuild tasks and targets for code generation + false + false + $(MSBuildProjectName).nuspec + Build Tasks;msbuild;DownloadFile;GetFilenameFromUri;code generation + GenerationTasks + netstandard2.0;net461 + + + + + + + + + + + + + + + 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); + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec new file mode 100644 index 0000000000..5b840bd379 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec @@ -0,0 +1,28 @@ + + + + $id$ + $authors$ + $copyright$ + $description$ + true + $iconUrl$ + $licenseUrl$ + 2.8 + $owners$ + $projectUrl$ + + false + $tags$ + $version$ + + + + + + + + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets b/src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets new file mode 100644 index 0000000000..5ed88a3f6c --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props new file mode 100644 index 0000000000..dc67dca96a --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props @@ -0,0 +1,133 @@ + + + + + <_GenerationTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 + <_GenerationTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' != 'Core'">net461 + <_GenerationTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_GenerationTasksAssemblyTarget)/GenerationTasks.dll + <_GenerationTasksAssemblyTarget /> + + + + + + + + true + $([MSBuild]::EnsureTrailingSlash('$(ServiceProjectReferenceDirectory)')) + + true + $([MSBuild]::EnsureTrailingSlash('$(ServiceUriReferenceDirectory)')) + + true + $([MSBuild]::EnsureTrailingSlash('$(ServiceFileReferenceDirectory)')) + $(RootNamespace) + $(RootNamespace) + + + _DefaultDocumentGenerator_GetMetadata; + _DefaultDocumentGenerator_Core; + _DefaultDocumentGenerator_SetMetadata + + + _ServiceProjectReferenceGenerator_GetTargetFramework; + _ServiceProjectReferenceGenerator_GetProjectTargetPath; + _ServiceProjectReferenceGenerator_Restore; + _ServiceProjectReferenceGenerator_Build; + _ServiceProjectReferenceGenerator_Core + + + _ServiceUriReferenceGenerator_GetMetadata; + _ServiceUriReferenceGenerator_Core + + + _CheckServiceReferences; + ServiceProjectReferenceGenerator; + ServiceUriReferenceGenerator; + _ServiceFileReferenceGenerator_GetMetadata; + _ServiceFileReferenceGenerator_Core + + + + + + + + Default + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(Filename)Client + + + + + + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets new file mode 100644 index 0000000000..7c70d7d279 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + <_FullPath>%(ServiceProjectReference.FullPath) + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + + + <_TargetFrameworks>%(_Temporary.TargetFrameworks) + <_TargetFramework>$(_TargetFrameworks.Split(';')[0]) + + + + $(_TargetFramework) + + <_Temporary Remove="@(_Temporary)" /> + + + + <_FullPath /> + <_TargetFramework /> + <_TargetFrameworks /> + + + + + + + + <_FullPath>%(ServiceProjectReference.FullPath) + <_TargetFramework>%(ServiceProjectReference.TargetFramework) + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + + + <_ProjectTargetPath>%(_Temporary.FullPath) + + + + $(_ProjectTargetPath) + + <_Temporary Remove="@(_Temporary)" /> + + + + <_FullPath /> + <_ProjectTargetPath /> + <_TargetFramework /> + + + + + + + + + + + + + + + + + + + + <_Temporary Remove="@(_Temporary)" /> + <_Temporary Include="@(ServiceProjectReference -> WithMetadataValue('DocumentGenerator', 'Default'))" /> + + + + + + + + + + <_Command>dotnet getdocument --configuration $(Configuration) --no-build + + + <_Temporary Update="@(_Temporary)"> + $(DefaultDocumentGeneratorDefaultOptions) + $(_Command) --project %(FullPath) --output %(DocumentPath) --framework %(TargetFramework) + + <_Temporary Update="@(_Temporary)"> + %(Command) --uri %(_Temporary.Uri) + + <_Temporary Update="@(_Temporary)"> + %(Command) --service %(_Temporary.Service) --method %(_Temporary.Method) + + <_Temporary Update="@(_Temporary)"> + %(Command) %(_Temporary.Options) + + + + + + + + + + + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + + + + + + + + + + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props b/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props new file mode 100644 index 0000000000..4269fdd11c --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props @@ -0,0 +1,20 @@ + + + + + _NSwagDocumentGenerator_GetMetadata; + _NSwagDocumentGenerator_Core; + _NSwagDocumentGenerator_SetMetadata + + + _NSwagCSharpCodeGenerator_GetMetadata; + _NSwagCSharpCodeGenerator_Core; + _NSwagCSharpCodeGenerator_SetMetadata + + + _NSwagTypeScriptCodeGenerator_GetMetadata; + _NSwagTypeScriptCodeGenerator_Core; + _NSwagTypeScriptCodeGenerator_SetMetadata + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets new file mode 100644 index 0000000000..e73cd8d641 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets @@ -0,0 +1,131 @@ + + + + + + + <_NSwagTemporary Remove="@(_NSwagTemporary)" /> + <_NSwagTemporary Include="@(ServiceProjectReference -> WithMetadataValue('DocumentGenerator', 'NSwag'))"> + $(NSwagDocumentGeneratorDefaultOptions) + + + + + + + + <_Command>$(NSwagExe_Core21) aspnetcore2swagger /Configuration:$(Configuration) /NoBuild:true + + + + + + + <_Command /> + + + + + + + + + <_NSwagTemporary Remove="@(_NSwagTemporary)" /> + + + + + + + + + + <_NSwagTemporary Remove="@(_NSwagTemporary)" /> + <_NSwagTemporary Include="@(ServiceFileReference -> WithMetadataValue('CodeGenerator', 'NSwagCSharp'))"> + $(NSwagCSharpCodeGeneratorDefaultOptions) + + <_NSwagTemporary Update="@(_NSwagTemporary)"> + $(ServiceFileReferenceDirectory)%(ClassName).cs + + + + + + + <_Command>$(NSwagExe_Core21) swagger2csclient /namespace:$(NSwagCSharpCodeGeneratorNamespace) + + + + + + + <_Command /> + + + + + + + + + + + <_NSwagTemporary Remove="@(_NSwagTemporary)" /> + + + + + + + + + + <_NSwagTemporary Remove="@(_NSwagTemporary)" /> + <_NSwagTemporary Include="@(ServiceFileReference -> WithMetadataValue('CodeGenerator', 'NSwagTypeScript'))"> + $(NSwagTypeScriptCodeGeneratorDefaultOptions) + + <_NSwagTemporary Update="@(_NSwagTemporary)"> + $(ServiceFileReferenceDirectory)%(ClassName).ts + + + + + + + <_Command>$(NSwagExe_Core21) swagger2tsclient /namespace:$(NSwagTypeScriptCodeGeneratorNamespace) + + + + + + + <_Command /> + + + + + + + + + <_NSwagTemporary Remove="@(_NSwagTemporary)" /> + + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets b/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets new file mode 100644 index 0000000000..5e73fd66e1 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/dotnet-getdocument/Commands/InvokeCommand.cs b/src/dotnet-getdocument/Commands/InvokeCommand.cs new file mode 100644 index 0000000000..cf3308ec46 --- /dev/null +++ b/src/dotnet-getdocument/Commands/InvokeCommand.cs @@ -0,0 +1,241 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Versioning; +using GetDocument.Properties; +using Microsoft.DotNet.Cli.CommandLine; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace GetDocument.Commands +{ + internal class InvokeCommand : HelpCommandBase + { + private const string InsideManName = "GetDocument.Insider"; + + private CommandOption _configuration; + private CommandOption _framework; + private CommandOption _msbuildprojectextensionspath; + private CommandOption _output; + private CommandOption _project; + private CommandOption _runtime; + private IList _args; + + public override void Configure(CommandLineApplication command) + { + var options = new ProjectOptions(); + options.Configure(command); + + _project = options.Project; + _framework = options.Framework; + _configuration = options.Configuration; + _runtime = options.Runtime; + _msbuildprojectextensionspath = options.MSBuildProjectExtensionsPath; + + _output = command.Option("--output ", Resources.OutputDescription); + command.VersionOption("--version", ProductInfo.GetVersion); + _args = command.RemainingArguments; + + base.Configure(command); + } + + protected override int Execute() + { + var projectFile = FindProjects( + _project.Value(), + Resources.NoProject, + Resources.MultipleProjects); + Reporter.WriteVerbose(Resources.UsingProject(projectFile)); + + var project = Project.FromFile( + projectFile, + _msbuildprojectextensionspath.Value(), + _framework.Value(), + _configuration.Value(), + _runtime.Value()); + if (!File.Exists(project.AssemblyPath)) + { + throw new CommandException(Resources.MustBuild); + } + + var thisPath = Path.GetFullPath(Path.GetDirectoryName(typeof(InvokeCommand).Assembly.Location)); + + string executable = null; + var cleanupExecutable = false; + try + { + string toolsDirectory; + var args = new List(); + var targetFramework = new FrameworkName(project.TargetFrameworkMoniker); + switch (targetFramework.Identifier) + { + case ".NETFramework": + cleanupExecutable = true; + executable = Path.Combine(project.OutputPath, InsideManName + ".exe"); + toolsDirectory = Path.Combine( + thisPath, + project.PlatformTarget == "x86" ? "net461-x86" : "net461"); + + var executableSource = Path.Combine(toolsDirectory, InsideManName + ".exe"); + File.Copy(executableSource, executable, overwrite: true); + + if (!string.IsNullOrEmpty(project.ConfigPath)) + { + File.Copy(project.ConfigPath, executable + ".config", overwrite: true); + } + break; + + case ".NETCoreApp": + executable = "dotnet"; + toolsDirectory = Path.Combine(thisPath, "netcoreapp2.0"); + + if (targetFramework.Version < new Version(2, 0)) + { + throw new CommandException( + Resources.NETCoreApp1Project(project.Name, targetFramework.Version)); + } + + args.Add("exec"); + args.Add("--depsFile"); + args.Add(project.DepsPath); + + if (!string.IsNullOrEmpty(project.AssetsPath)) + { + using (var reader = new JsonTextReader(File.OpenText(project.AssetsPath))) + { + var projectAssets = JToken.ReadFrom(reader); + var packageFolders = projectAssets["packageFolders"] + .Children() + .Select(p => p.Name); + + foreach (var packageFolder in packageFolders) + { + args.Add("--additionalProbingPath"); + args.Add(packageFolder.TrimEnd(Path.DirectorySeparatorChar)); + } + } + } + + if (File.Exists(project.RuntimeConfigPath)) + { + args.Add("--runtimeConfig"); + args.Add(project.RuntimeConfigPath); + } + else if (!string.IsNullOrEmpty(project.RuntimeFrameworkVersion)) + { + args.Add("--fx-version"); + args.Add(project.RuntimeFrameworkVersion); + } + + args.Add(Path.Combine(toolsDirectory, InsideManName + ".dll")); + break; + + case ".NETStandard": + throw new CommandException(Resources.NETStandardProject(project.Name)); + + default: + throw new CommandException( + Resources.UnsupportedFramework(project.Name, targetFramework.Identifier)); + } + + args.AddRange(_args); + args.Add("--assembly"); + args.Add(project.AssemblyPath); + args.Add("--tools-directory"); + args.Add(toolsDirectory); + + if (!(args.Contains("--method") || string.IsNullOrEmpty(project.DefaultMethod))) + { + args.Add("--method"); + args.Add(project.DefaultMethod); + } + + if (!(args.Contains("--service") || string.IsNullOrEmpty(project.DefaultService))) + { + args.Add("--service"); + args.Add(project.DefaultService); + } + + if (!(args.Contains("--uri") || string.IsNullOrEmpty(project.DefaultUri))) + { + args.Add("--uri"); + args.Add(project.DefaultUri); + } + + if (_output.HasValue()) + { + args.Add("--output"); + args.Add(Path.GetFullPath(_output.Value())); + } + + if (Reporter.IsVerbose) + { + args.Add("--verbose"); + } + + if (Reporter.NoColor) + { + args.Add("--no-color"); + } + + if (Reporter.PrefixOutput) + { + args.Add("--prefix-output"); + } + + return Exe.Run(executable, args, project.Directory); + } + finally + { + if (cleanupExecutable && !string.IsNullOrEmpty(executable)) + { + File.Delete(executable); + File.Delete(executable + ".config"); + } + } + } + + private static string FindProjects( + string path, + string errorWhenNoProject, + string errorWhenMultipleProjects) + { + var specified = true; + if (path == null) + { + specified = false; + path = Directory.GetCurrentDirectory(); + } + else if (!Directory.Exists(path)) // It's not a directory + { + return path; + } + + var projectFiles = Directory + .EnumerateFiles(path, "*.*proj", SearchOption.TopDirectoryOnly) + .Where(f => !string.Equals(Path.GetExtension(f), ".xproj", StringComparison.OrdinalIgnoreCase)) + .Take(2) + .ToList(); + if (projectFiles.Count == 0) + { + throw new CommandException( + specified + ? Resources.NoProjectInDirectory(path) + : errorWhenNoProject); + } + if (projectFiles.Count != 1) + { + throw new CommandException( + specified + ? Resources.MultipleProjectsInDirectory(path) + : errorWhenMultipleProjects); + } + + return projectFiles[0]; + } + } +} diff --git a/src/dotnet-getdocument/Exe.cs b/src/dotnet-getdocument/Exe.cs new file mode 100644 index 0000000000..0c8f7d89ae --- /dev/null +++ b/src/dotnet-getdocument/Exe.cs @@ -0,0 +1,118 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace GetDocument +{ + internal static class Exe + { + public static int Run( + string executable, + IReadOnlyList 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 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(); + } + } +} diff --git a/src/dotnet-getdocument/Program.cs b/src/dotnet-getdocument/Program.cs new file mode 100644 index 0000000000..495573a776 --- /dev/null +++ b/src/dotnet-getdocument/Program.cs @@ -0,0 +1,43 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using GetDocument.Commands; +using GetDocument.Properties; +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument +{ + internal static class Program + { + private static int Main(string[] args) + { + var app = new CommandLineApplication(throwOnUnexpectedArg: false) + { + FullName = Resources.CommandFullName, + }; + + new InvokeCommand().Configure(app); + + try + { + return app.Execute(args); + } + catch (Exception ex) + { + if (ex is CommandException || ex is CommandParsingException) + { + Reporter.WriteVerbose(ex.ToString()); + } + else + { + Reporter.WriteInformation(ex.ToString()); + } + + Reporter.WriteError(ex.Message); + + return 1; + } + } + } +} diff --git a/src/dotnet-getdocument/Project.cs b/src/dotnet-getdocument/Project.cs new file mode 100644 index 0000000000..274960a08b --- /dev/null +++ b/src/dotnet-getdocument/Project.cs @@ -0,0 +1,228 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using GetDocument.Properties; +using IODirectory = System.IO.Directory; + +namespace GetDocument +{ + internal class Project + { + private const string MSBuildResourceName = "GetDocument.ServiceProjectReferenceMetadata"; + + private Project() + { + } + + public string AssemblyName { get; private set; } + + public string AssemblyPath { get; private set; } + + public string AssetsPath { get; private set; } + + public string Configuration { get; private set; } + + public string ConfigPath { get; private set; } + + public string DefaultDocumentName { get; private set; } + + public string DefaultMethod { get; private set; } + + public string DefaultService { get; private set; } + + public string DefaultUri { get; private set; } + + public string DepsPath { get; private set; } + + public string Directory { get; private set; } + + public string ExtensionsPath { get; private set; } + + public string Name { get; private set; } + + public string OutputPath { get; private set; } + + public string Platform { get; private set; } + + public string PlatformTarget { get; private set; } + + public string RuntimeConfigPath { get; private set; } + + public string RuntimeFrameworkVersion { get; private set; } + + public string TargetFramework { get; private set; } + + public string TargetFrameworkMoniker { get; private set; } + + public static Project FromFile( + string file, + string buildExtensionsDirectory, + string framework = null, + string configuration = null, + string runtime = null) + { + Debug.Assert(!string.IsNullOrEmpty(file), "file is null or empty."); + + if (string.IsNullOrEmpty(buildExtensionsDirectory)) + { + buildExtensionsDirectory = Path.Combine(Path.GetDirectoryName(file), "obj"); + } + + IODirectory.CreateDirectory(buildExtensionsDirectory); + + var assembly = typeof(Project).Assembly; + var propsPath = Path.Combine( + buildExtensionsDirectory, + Path.GetFileName(file) + ".ServiceProjectReferenceMetadata.props"); + using (var input = assembly.GetManifestResourceStream($"{MSBuildResourceName}.props")) + { + using (var output = File.OpenWrite(propsPath)) + { + Reporter.WriteVerbose(Resources.WritingFile(propsPath)); + input.CopyTo(output); + } + } + + var targetsPath = Path.ChangeExtension(propsPath, ".targets"); + using (var input = assembly.GetManifestResourceStream($"{MSBuildResourceName}.targets")) + { + using (var output = File.OpenWrite(targetsPath)) + { + // NB: Copy always in case it changes + Reporter.WriteVerbose(Resources.WritingFile(targetsPath)); + input.CopyTo(output); + } + } + + IDictionary metadata; + var metadataPath = Path.GetTempFileName(); + try + { + var propertyArg = "/property:ServiceProjectReferenceMetadataPath=" + metadataPath; + if (!string.IsNullOrEmpty(framework)) + { + propertyArg += ";TargetFramework=" + framework; + } + if (!string.IsNullOrEmpty(configuration)) + { + propertyArg += ";Configuration=" + configuration; + } + if (!string.IsNullOrEmpty(runtime)) + { + propertyArg += ";RuntimeIdentifier=" + runtime; + } + + var args = new List + { + "msbuild", + "/target:WriteServiceProjectReferenceMetadata", + propertyArg, + "/verbosity:quiet", + "/nologo" + }; + + if (!string.IsNullOrEmpty(file)) + { + args.Add(file); + } + + var exitCode = Exe.Run("dotnet", args); + if (exitCode != 0) + { + throw new CommandException(Resources.GetMetadataFailed); + } + + metadata = File.ReadLines(metadataPath).Select(l => l.Split(new[] { ':' }, 2)) + .ToDictionary(s => s[0], s => s[1].TrimStart()); + } + finally + { + File.Delete(propsPath); + File.Delete(metadataPath); + File.Delete(targetsPath); + } + + var project = new Project + { + AssemblyName = metadata[nameof(AssemblyName)], + AssemblyPath = metadata[nameof(AssemblyPath)], + AssetsPath = metadata[nameof(AssetsPath)], + Configuration = metadata[nameof(Configuration)], + DefaultDocumentName = metadata[nameof(DefaultDocumentName)], + DefaultMethod = metadata[nameof(DefaultMethod)], + DefaultService = metadata[nameof(DefaultService)], + DefaultUri = metadata[nameof(DefaultUri)], + DepsPath = metadata[nameof(DepsPath)], + Directory = metadata[nameof(Directory)], + ExtensionsPath = metadata[nameof(ExtensionsPath)], + Name = metadata[nameof(Name)], + OutputPath = metadata[nameof(OutputPath)], + Platform = metadata[nameof(Platform)], + PlatformTarget = metadata[nameof(PlatformTarget)] ?? metadata[nameof(Platform)], + RuntimeConfigPath = metadata[nameof(RuntimeConfigPath)], + RuntimeFrameworkVersion = metadata[nameof(RuntimeFrameworkVersion)], + TargetFramework = metadata[nameof(TargetFramework)], + TargetFrameworkMoniker = metadata[nameof(TargetFrameworkMoniker)], + }; + + if (string.IsNullOrEmpty(project.AssemblyPath)) + { + throw new CommandException(Resources.GetMetadataValueFailed(nameof(AssemblyPath), "TargetPath")); + } + + if (string.IsNullOrEmpty(project.Directory)) + { + throw new CommandException(Resources.GetMetadataValueFailed(nameof(Directory), "ProjectDir")); + } + + if (string.IsNullOrEmpty(project.OutputPath)) + { + throw new CommandException(Resources.GetMetadataValueFailed(nameof(OutputPath), "OutDir")); + } + + if (!Path.IsPathRooted(project.Directory)) + { + project.Directory = Path.GetFullPath(Path.Combine(IODirectory.GetCurrentDirectory(), project.Directory)); + } + + if (!Path.IsPathRooted(project.AssemblyPath)) + { + project.AssemblyPath = Path.GetFullPath(Path.Combine(project.Directory, project.AssemblyPath)); + } + + if (!Path.IsPathRooted(project.OutputPath)) + { + project.OutputPath = Path.GetFullPath(Path.Combine(project.Directory, project.OutputPath)); + } + + // Some document generation tools support non-ASP.NET Core projects. + // Thus any of the remaining properties may be empty. + if (!(string.IsNullOrEmpty(project.AssetsPath) || Path.IsPathRooted(project.AssetsPath))) + { + project.AssetsPath = Path.GetFullPath(Path.Combine(project.Directory, project.AssetsPath)); + } + + var configPath = $"{project.AssemblyPath}.config"; + if (File.Exists(configPath)) + { + project.ConfigPath = configPath; + } + + if (!(string.IsNullOrEmpty(project.DepsPath) || Path.IsPathRooted(project.DepsPath))) + { + project.DepsPath = Path.GetFullPath(Path.Combine(project.Directory, project.DepsPath)); + } + + if (!(string.IsNullOrEmpty(project.RuntimeConfigPath) || Path.IsPathRooted(project.RuntimeConfigPath))) + { + project.RuntimeConfigPath = Path.GetFullPath(Path.Combine(project.Directory, project.RuntimeConfigPath)); + } + + return project; + } + } +} diff --git a/src/dotnet-getdocument/ProjectOptions.cs b/src/dotnet-getdocument/ProjectOptions.cs new file mode 100644 index 0000000000..bca160eeaa --- /dev/null +++ b/src/dotnet-getdocument/ProjectOptions.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using GetDocument.Properties; +using Microsoft.DotNet.Cli.CommandLine; + +namespace GetDocument +{ + internal class ProjectOptions + { + public CommandOption Project { get; private set; } + + public CommandOption Framework { get; private set; } + + public CommandOption Configuration { get; private set; } + + public CommandOption Runtime { get; private set; } + + public CommandOption MSBuildProjectExtensionsPath { get; private set; } + + public void Configure(CommandLineApplication command) + { + Project = command.Option("-p|--project ", Resources.ProjectDescription); + Framework = command.Option("--framework ", Resources.FrameworkDescription); + Configuration = command.Option("--configuration ", Resources.ConfigurationDescription); + Runtime = command.Option("--runtime ", Resources.RuntimeDescription); + MSBuildProjectExtensionsPath = command.Option("--msbuildprojectextensionspath ", Resources.ProjectExtensionsDescription); + } + } +} diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.cs b/src/dotnet-getdocument/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..3ee7f0ba79 --- /dev/null +++ b/src/dotnet-getdocument/Properties/Resources.Designer.cs @@ -0,0 +1,179 @@ +// + +using System; +using System.Reflection; +using System.Resources; +using JetBrains.Annotations; + +namespace GetDocument.Properties +{ + /// + /// This API supports the GetDocument infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("GetDocument.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// The configuration to use. + /// + public static string ConfigurationDescription + => GetString("ConfigurationDescription"); + + /// + /// dotnet getdocument + /// + public static string CommandFullName + => GetString("CommandFullName"); + + /// + /// The target framework. + /// + public static string FrameworkDescription + => GetString("FrameworkDescription"); + + /// + /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. + /// + public static string GetMetadataFailed + => GetString("GetMetadataFailed"); + + /// + /// More than one project was found in the current working directory. Use the --project option. + /// + public static string MultipleProjects + => GetString("MultipleProjects"); + + /// + /// More than one project was found in directory '{projectDirectory}'. Specify one using its file name. + /// + public static string MultipleProjectsInDirectory([CanBeNull] object projectDirectory) + => string.Format( + GetString("MultipleProjectsInDirectory", nameof(projectDirectory)), + projectDirectory); + + /// + /// Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the GetDocument Command-line Tool only supports version 2.0 or higher. + /// + public static string NETCoreApp1Project([CanBeNull] object Project, [CanBeNull] object targetFrameworkVersion) + => string.Format( + GetString("NETCoreApp1Project", nameof(Project), nameof(targetFrameworkVersion)), + Project, targetFrameworkVersion); + + /// + /// Project '{Project}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the GetDocument Command-line Tool with this project, add an executable project targeting .NET Core or .NET Framework that references this project and specify it using the --project option; or, update this project to target .NET Core and / or .NET Framework. + /// + public static string NETStandardProject([CanBeNull] object Project) + => string.Format( + GetString("NETStandardProject", nameof(Project)), + Project); + + /// + /// Do not colorize output. + /// + public static string NoColorDescription + => GetString("NoColorDescription"); + + /// + /// No project was found. Change the current working directory or use the --project option. + /// + public static string NoProject + => GetString("NoProject"); + + /// + /// No project was found in directory '{projectDirectory}'. + /// + public static string NoProjectInDirectory([CanBeNull] object projectDirectory) + => string.Format( + GetString("NoProjectInDirectory", nameof(projectDirectory)), + projectDirectory); + + /// + /// Prefix output with level. + /// + public static string PrefixDescription + => GetString("PrefixDescription"); + + /// + /// The project to use. + /// + public static string ProjectDescription + => GetString("ProjectDescription"); + + /// + /// The MSBuild project extensions path. Defaults to "obj". + /// + public static string ProjectExtensionsDescription + => GetString("ProjectExtensionsDescription"); + + /// + /// The runtime identifier to use. + /// + public static string RuntimeDescription + => GetString("RuntimeDescription"); + + /// + /// Project '{Project}' targets framework '{targetFramework}'. The GetDocument Command-line Tool does not support this framework. + /// + public static string UnsupportedFramework([CanBeNull] object Project, [CanBeNull] object targetFramework) + => string.Format( + GetString("UnsupportedFramework", nameof(Project), nameof(targetFramework)), + Project, targetFramework); + + /// + /// Using project '{project}'. + /// + public static string UsingProject([CanBeNull] object project) + => string.Format( + GetString("UsingProject", nameof(project)), + project); + + /// + /// Show verbose output. + /// + public static string VerboseDescription + => GetString("VerboseDescription"); + + /// + /// Writing '{file}'... + /// + public static string WritingFile([CanBeNull] object file) + => string.Format( + GetString("WritingFile", nameof(file)), + file); + + /// + /// Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + /// + public static string MustBuild + => GetString("MustBuild"); + + /// + /// The file to write the result to. + /// + public static string OutputDescription + => GetString("OutputDescription"); + + /// + /// Unable to retrieve '{properrty}' project metadata. Ensure '{msbuildProperty}' is set. + /// + public static string GetMetadataValueFailed([CanBeNull] object properrty, [CanBeNull] object msbuildProperty) + => string.Format( + GetString("GetMetadataValueFailed", nameof(properrty), nameof(msbuildProperty)), + properrty, msbuildProperty); + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + + return value; + } + } +} + diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.tt b/src/dotnet-getdocument/Properties/Resources.Designer.tt new file mode 100644 index 0000000000..3f636a4db5 --- /dev/null +++ b/src/dotnet-getdocument/Properties/Resources.Designer.tt @@ -0,0 +1,6 @@ +<# + Session["ResourceFile"] = "Resources.resx"; + Session["AccessModifier"] = "internal"; + Session["NoDiagnostics"] = true; +#> +<#@ include file="..\..\tools\Resources.tt" #> diff --git a/src/dotnet-getdocument/Properties/Resources.resx b/src/dotnet-getdocument/Properties/Resources.resx new file mode 100644 index 0000000000..16e16b8086 --- /dev/null +++ b/src/dotnet-getdocument/Properties/Resources.resx @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The configuration to use. + + + dotnet getdocument + + + The target framework. + + + Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. + + + More than one project was found in the current working directory. Use the --project option. + + + More than one project was found in directory '{projectDirectory}'. Specify one using its file name. + + + Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the GetDocument Command-line Tool only supports version 2.0 or higher. + + + Project '{Project}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the GetDocument Command-line Tool with this project, add an executable project targeting .NET Core or .NET Framework that references this project and specify it using the --project option; or, update this project to target .NET Core and / or .NET Framework. + + + Do not colorize output. + + + No project was found. Change the current working directory or use the --project option. + + + No project was found in directory '{projectDirectory}'. + + + Prefix output with level. + + + The project to use. + + + The MSBuild project extensions path. Defaults to "obj". + + + The runtime identifier to use. + + + Project '{Project}' targets framework '{targetFramework}'. The GetDocument Command-line Tool does not support this framework. + + + Using project '{project}'. + + + Show verbose output. + + + Writing '{file}'... + + + Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + + + The file to write the result to. + + + Unable to retrieve '{properrty}' project metadata. Ensure '{msbuildProperty}' is set. + + \ No newline at end of file diff --git a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.props b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.props new file mode 100644 index 0000000000..30f045f3c0 --- /dev/null +++ b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.props @@ -0,0 +1,17 @@ + + + + + + $(WriteServiceProjectReferenceMetadataDependsOn) + + + + + $(WriteServiceProjectReferenceMetadataDependsOn) + + + $(WriteServiceProjectReferenceMetadataDependsOn) + + + diff --git a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets new file mode 100644 index 0000000000..e8840ea37b --- /dev/null +++ b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/dotnet-getdocument/dotnet-getdocument.csproj b/src/dotnet-getdocument/dotnet-getdocument.csproj new file mode 100644 index 0000000000..b88db8367a --- /dev/null +++ b/src/dotnet-getdocument/dotnet-getdocument.csproj @@ -0,0 +1,112 @@ + + + + + + + $(GenerateNuspecDependsOn);PopulateNuspec + + dotnet-getdocument + GetDocument Command-line Tool outside man + false + true + false + false + $(MSBuildProjectName).nuspec + Exe + true + GetDocument;command line;command-line;tool + GetDocument + netcoreapp2.1 + + + + + + + + + + + + + + + + + + + + + + + + + + TextTemplatingFileGenerator + Resources.Designer.cs + + + + + + + + + + True + True + Resources.Designer.tt + + + + + + + + + + + + + + + + <_Temporary Remove="@(Temporary)" /> + <_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=net461" /> + <_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=net461;Platform=x86" /> + <_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=netcoreapp2.0" /> + + + + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + authors=$(Authors); + copyright=$(Copyright); + description=$(Description); + iconUrl=$(PackageIconUrl); + id=$(PackageId); + InsiderNet461Output=..\GetDocumentInsider\bin\$(Configuration)\net461\publish\*; + InsiderNet461X86Output=..\GetDocumentInsider\bin\x86\$(Configuration)\net461\publish\*; + InsiderNetCoreOutput=..\GetDocumentInsider\bin\$(Configuration)\netcoreapp2.0\publish\*; + licenseUrl=$(PackageLicenseUrl); + Output=$(PublishDir)**\*; + OutputShims=$(IntermediateOutputPath)shims\**\*; + packageType=$(PackageType); + projectUrl=$(PackageProjectUrl); + repositoryCommit=$(RepositoryCommit); + repositoryUrl=$(RepositoryUrl); + SettingsFile=$(_ToolsSettingsFilePath); + tags=$(PackageTags.Replace(';', ' ')); + targetFramework=$(TargetFramework); + version=$(PackageVersion); + + + + diff --git a/src/dotnet-getdocument/dotnet-getdocument.nuspec b/src/dotnet-getdocument/dotnet-getdocument.nuspec new file mode 100644 index 0000000000..60c51f7869 --- /dev/null +++ b/src/dotnet-getdocument/dotnet-getdocument.nuspec @@ -0,0 +1,28 @@ + + + + $id$ + $version$ + $authors$ + true + $licenseUrl$ + $projectUrl$ + $iconUrl$ + $description$ + $copyright$ + $tags$ + + + + + + + + + + + + + + + From 25d0916b493d4698ee2d0ece5319c10cad537473 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 6 Sep 2018 09:25:54 -0700 Subject: [PATCH 02/14] Use one namespace for the three client code generation projects - also cleared out most uses of `GetDocument` and `GenerationTasks` in MSBuild and strings - temporarily fixed up T4 templates, adding Resources.tt (will remove custom generation soon) --- src/GetDocumentInsider/AnsiConsole.cs | 2 +- src/GetDocumentInsider/AnsiConstants.cs | 2 +- src/GetDocumentInsider/AnsiTextWriter.cs | 2 +- src/GetDocumentInsider/CommandException.cs | 2 +- .../Commands/CommandBase.cs | 4 +- .../Commands/GetDocumentCommand.cs | 6 +- .../Commands/GetDocumentCommandContext.cs | 2 +- .../Commands/GetDocumentCommandWorker.cs | 5 +- .../Commands/HelpCommandBase.cs | 2 +- .../Commands/ProjectCommandBase.cs | 4 +- .../GetDocumentInsider.csproj | 2 +- src/GetDocumentInsider/Json.cs | 4 +- src/GetDocumentInsider/LogWrapper.cs | 3 +- src/GetDocumentInsider/ProductInfo.cs | 12 +- src/GetDocumentInsider/Program.cs | 6 +- .../Properties/Resources.Designer.cs | 4 +- .../Properties/Resources.Designer.tt | 2 +- src/GetDocumentInsider/Reporter.cs | 4 +- src/GetDocumentInsider/WrappedException.cs | 2 +- .../DownloadFile.cs | 2 +- .../DownloadFileCore.cs | 2 +- .../GetFileReferenceMetadata.cs | 2 +- .../GetProjectReferenceMetadata.cs | 2 +- .../GetUriReferenceMetadata.cs | 2 +- .../ILogWrapper.cs | 2 +- .../LogWrapper.cs | 2 +- ...ft.Extensions.ApiDescription.Client.csproj | 1 - .../build/GenerationTasks.props | 16 +- .../build/GenerationTasks.targets | 10 +- .../Commands/InvokeCommand.cs | 4 +- src/dotnet-getdocument/Exe.cs | 2 +- src/dotnet-getdocument/Program.cs | 6 +- src/dotnet-getdocument/Project.cs | 6 +- src/dotnet-getdocument/ProjectOptions.cs | 4 +- .../Properties/Resources.Designer.cs | 12 +- .../Properties/Resources.Designer.tt | 2 +- .../Properties/Resources.resx | 8 +- .../dotnet-getdocument.csproj | 2 +- tools/Resources.tt | 226 ++++++++++++++++++ 39 files changed, 299 insertions(+), 84 deletions(-) create mode 100644 tools/Resources.tt diff --git a/src/GetDocumentInsider/AnsiConsole.cs b/src/GetDocumentInsider/AnsiConsole.cs index 30397229aa..c3f514bde4 100644 --- a/src/GetDocumentInsider/AnsiConsole.cs +++ b/src/GetDocumentInsider/AnsiConsole.cs @@ -3,7 +3,7 @@ using System; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal class AnsiConsole { diff --git a/src/GetDocumentInsider/AnsiConstants.cs b/src/GetDocumentInsider/AnsiConstants.cs index e529180983..48f9ca2410 100644 --- a/src/GetDocumentInsider/AnsiConstants.cs +++ b/src/GetDocumentInsider/AnsiConstants.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal static class AnsiConstants { diff --git a/src/GetDocumentInsider/AnsiTextWriter.cs b/src/GetDocumentInsider/AnsiTextWriter.cs index c8393d4810..471d9cf124 100644 --- a/src/GetDocumentInsider/AnsiTextWriter.cs +++ b/src/GetDocumentInsider/AnsiTextWriter.cs @@ -6,7 +6,7 @@ using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal class AnsiTextWriter { diff --git a/src/GetDocumentInsider/CommandException.cs b/src/GetDocumentInsider/CommandException.cs index 5d9778e61f..18680f9593 100644 --- a/src/GetDocumentInsider/CommandException.cs +++ b/src/GetDocumentInsider/CommandException.cs @@ -3,7 +3,7 @@ using System; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal class CommandException : Exception { diff --git a/src/GetDocumentInsider/Commands/CommandBase.cs b/src/GetDocumentInsider/Commands/CommandBase.cs index 4f66e51d5e..61e83151ce 100644 --- a/src/GetDocumentInsider/Commands/CommandBase.cs +++ b/src/GetDocumentInsider/Commands/CommandBase.cs @@ -1,10 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using GetDocument.Properties; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Properties; -namespace GetDocument.Commands +namespace Microsoft.Extensions.ApiDescription.Client.Commands { internal abstract class CommandBase { diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs index f615e4399b..af61b02af6 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs @@ -8,17 +8,17 @@ using System.Reflection; #if NETCOREAPP2_0 using System.Runtime.Loader; #endif -using GetDocument.Properties; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Properties; -namespace GetDocument.Commands +namespace Microsoft.Extensions.ApiDescription.Client.Commands { internal class GetDocumentCommand : ProjectCommandBase { internal const string FallbackDocumentName = "v1"; internal const string FallbackMethod = "Generate"; internal const string FallbackService = "Microsoft.Extensions.ApiDescription.IDocumentProvider"; - private const string WorkerType = "GetDocument.Commands.GetDocumentCommandWorker"; + private const string WorkerType = "Microsoft.Extensions.ApiDescription.Client.Commands.GetDocumentCommandWorker"; private CommandOption _documentName; private CommandOption _method; diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs index 996e9e9701..65b3589af2 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs @@ -1,6 +1,6 @@ using System; -namespace GetDocument.Commands +namespace Microsoft.Extensions.ApiDescription.Client.Commands { [Serializable] public class GetDocumentCommandContext diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs index c010165e61..97a1f4e809 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs @@ -4,14 +4,13 @@ using System.IO; using System.Reflection; using System.Threading; using System.Threading.Tasks; -using GenerationTasks; -using GetDocument.Properties; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.ApiDescription.Client.Properties; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -namespace GetDocument.Commands +namespace Microsoft.Extensions.ApiDescription.Client.Commands { internal class GetDocumentCommandWorker { diff --git a/src/GetDocumentInsider/Commands/HelpCommandBase.cs b/src/GetDocumentInsider/Commands/HelpCommandBase.cs index 7e2c89cb5a..3f80564d54 100644 --- a/src/GetDocumentInsider/Commands/HelpCommandBase.cs +++ b/src/GetDocumentInsider/Commands/HelpCommandBase.cs @@ -3,7 +3,7 @@ using Microsoft.DotNet.Cli.CommandLine; -namespace GetDocument.Commands +namespace Microsoft.Extensions.ApiDescription.Client.Commands { internal class HelpCommandBase : CommandBase { diff --git a/src/GetDocumentInsider/Commands/ProjectCommandBase.cs b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs index a1a762f96c..71e74947d0 100644 --- a/src/GetDocumentInsider/Commands/ProjectCommandBase.cs +++ b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs @@ -1,10 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using GetDocument.Properties; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Properties; -namespace GetDocument.Commands +namespace Microsoft.Extensions.ApiDescription.Client.Commands { internal abstract class ProjectCommandBase : HelpCommandBase { diff --git a/src/GetDocumentInsider/GetDocumentInsider.csproj b/src/GetDocumentInsider/GetDocumentInsider.csproj index 8fe28cd313..abd288edd7 100644 --- a/src/GetDocumentInsider/GetDocumentInsider.csproj +++ b/src/GetDocumentInsider/GetDocumentInsider.csproj @@ -4,7 +4,7 @@ GetDocument Command-line Tool inside man false Exe - GetDocument + Microsoft.Extensions.ApiDescription.Client netcoreapp2.0;net461 diff --git a/src/GetDocumentInsider/Json.cs b/src/GetDocumentInsider/Json.cs index acb62e449f..7e93ac21cd 100644 --- a/src/GetDocumentInsider/Json.cs +++ b/src/GetDocumentInsider/Json.cs @@ -1,10 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using GetDocument.Properties; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Properties; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal static class Json { diff --git a/src/GetDocumentInsider/LogWrapper.cs b/src/GetDocumentInsider/LogWrapper.cs index 0ab10cb744..b4ee5b4f9b 100644 --- a/src/GetDocumentInsider/LogWrapper.cs +++ b/src/GetDocumentInsider/LogWrapper.cs @@ -1,7 +1,6 @@ using System; -using GenerationTasks; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { public class LogWrapper : ILogWrapper { diff --git a/src/GetDocumentInsider/ProductInfo.cs b/src/GetDocumentInsider/ProductInfo.cs index 22045ee0df..8db001423a 100644 --- a/src/GetDocumentInsider/ProductInfo.cs +++ b/src/GetDocumentInsider/ProductInfo.cs @@ -3,18 +3,10 @@ using System.Reflection; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { - /// - /// This API supports the GetDocument infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - public static class ProductInfo + internal static class ProductInfo { - /// - /// This API supports the GetDocument infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// public static string GetVersion() => typeof(ProductInfo) .Assembly diff --git a/src/GetDocumentInsider/Program.cs b/src/GetDocumentInsider/Program.cs index 935fca4de0..2f2f43a4c0 100644 --- a/src/GetDocumentInsider/Program.cs +++ b/src/GetDocumentInsider/Program.cs @@ -3,10 +3,10 @@ using System; using System.Text; -using GetDocument.Commands; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Commands; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal static class Program { @@ -33,7 +33,7 @@ namespace GetDocument if (ex is CommandException || ex is CommandParsingException || (ex is WrappedException wrappedException - && wrappedException.Type == "GetDocument.Design.OperationException")) + && wrappedException.Type == "Microsoft.Extensions.ApiDescription.Client.Design.OperationException")) { Reporter.WriteVerbose(ex.ToString()); } diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.cs b/src/GetDocumentInsider/Properties/Resources.Designer.cs index 90463782ab..7f3066776c 100644 --- a/src/GetDocumentInsider/Properties/Resources.Designer.cs +++ b/src/GetDocumentInsider/Properties/Resources.Designer.cs @@ -5,7 +5,7 @@ using System.Reflection; using System.Resources; using JetBrains.Annotations; -namespace GetDocument.Properties +namespace Microsoft.Extensions.ApiDescription.Client.Properties { /// /// This API supports the GetDocument infrastructure and is not intended to be used @@ -14,7 +14,7 @@ namespace GetDocument.Properties internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("GetDocument.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); /// /// The assembly to use. diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.tt b/src/GetDocumentInsider/Properties/Resources.Designer.tt index 3f636a4db5..29bb487272 100644 --- a/src/GetDocumentInsider/Properties/Resources.Designer.tt +++ b/src/GetDocumentInsider/Properties/Resources.Designer.tt @@ -3,4 +3,4 @@ Session["AccessModifier"] = "internal"; Session["NoDiagnostics"] = true; #> -<#@ include file="..\..\tools\Resources.tt" #> +<#@ include file="..\..\..\tools\Resources.tt" #> diff --git a/src/GetDocumentInsider/Reporter.cs b/src/GetDocumentInsider/Reporter.cs index b7c0c264a5..abfec580fb 100644 --- a/src/GetDocumentInsider/Reporter.cs +++ b/src/GetDocumentInsider/Reporter.cs @@ -3,9 +3,9 @@ using System; using System.Linq; -using static GetDocument.AnsiConstants; +using static Microsoft.Extensions.ApiDescription.Client.AnsiConstants; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal static class Reporter { diff --git a/src/GetDocumentInsider/WrappedException.cs b/src/GetDocumentInsider/WrappedException.cs index 7cd7bfc0d3..ec90fb6061 100644 --- a/src/GetDocumentInsider/WrappedException.cs +++ b/src/GetDocumentInsider/WrappedException.cs @@ -3,7 +3,7 @@ using System; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal class WrappedException : Exception { diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs index a1341e0581..1e79fd9722 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs @@ -11,7 +11,7 @@ using Microsoft.Build.Utilities; using Task = System.Threading.Tasks.Task; using Utilities = Microsoft.Build.Utilities; -namespace GenerationTasks +namespace Microsoft.Extensions.ApiDescription.Client { /// /// Downloads a file. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs index bf8156e32f..5fd655fb85 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs @@ -6,7 +6,7 @@ using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; -namespace GenerationTasks +namespace Microsoft.Extensions.ApiDescription.Client { internal static class DownloadFileCore { diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs index 6ae50f8b21..2c0717b695 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs @@ -4,7 +4,7 @@ using System.IO; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace GenerationTasks +namespace Microsoft.Extensions.ApiDescription.Client { /// /// Adds or corrects Namespace and OutputPath metadata in ServiceFileReference items. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs index e8ac95a819..379e674787 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs @@ -4,7 +4,7 @@ using System.IO; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace GenerationTasks +namespace Microsoft.Extensions.ApiDescription.Client { /// /// Adds or corrects DocumentPath and project-related metadata in ServiceProjectReference items. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs index 7d922e19dc..fc0f836ca0 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs @@ -4,7 +4,7 @@ using System.IO; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace GenerationTasks +namespace Microsoft.Extensions.ApiDescription.Client { /// /// Adds or corrects DocumentPath metadata in ServiceUriReference items. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs b/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs index 7c773ab359..8f7f66396d 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs @@ -1,6 +1,6 @@ using System; -namespace GenerationTasks +namespace Microsoft.Extensions.ApiDescription.Client { internal interface ILogWrapper { diff --git a/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs b/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs index 75ae1407a8..98358ee91b 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs @@ -1,7 +1,7 @@ using System; using Microsoft.Build.Utilities; -namespace GenerationTasks +namespace Microsoft.Extensions.ApiDescription.Client { internal class LogWrapper : ILogWrapper { diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj index 5dab6ea1aa..3041a7ea51 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj +++ b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj @@ -11,7 +11,6 @@ false $(MSBuildProjectName).nuspec Build Tasks;msbuild;DownloadFile;GetFilenameFromUri;code generation - GenerationTasks netstandard2.0;net461 diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props index dc67dca96a..989e7d9b23 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props @@ -2,15 +2,15 @@ - <_GenerationTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 - <_GenerationTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' != 'Core'">net461 - <_GenerationTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_GenerationTasksAssemblyTarget)/GenerationTasks.dll - <_GenerationTasksAssemblyTarget /> + <_ApiDescriptionTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 + <_ApiDescriptionTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' != 'Core'">net461 + <_ApiDescriptionTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_ApiDescriptionTasksAssemblyTarget)/Microsoft.Extensions.ApiDescription.Client.dll + <_ApiDescriptionTasksAssemblyTarget /> - - - - + + + + true diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets index 7c70d7d279..1b9b1ac184 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets @@ -184,9 +184,9 @@ <_Temporary Remove="@(_Temporary)" /> - + - + @@ -196,7 +196,7 @@ - @@ -215,9 +215,9 @@ <_Temporary Remove="@(_Temporary)" /> - + - + diff --git a/src/dotnet-getdocument/Commands/InvokeCommand.cs b/src/dotnet-getdocument/Commands/InvokeCommand.cs index cf3308ec46..f28aafacf4 100644 --- a/src/dotnet-getdocument/Commands/InvokeCommand.cs +++ b/src/dotnet-getdocument/Commands/InvokeCommand.cs @@ -6,12 +6,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Versioning; -using GetDocument.Properties; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Properties; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace GetDocument.Commands +namespace Microsoft.Extensions.ApiDescription.Client.Commands { internal class InvokeCommand : HelpCommandBase { diff --git a/src/dotnet-getdocument/Exe.cs b/src/dotnet-getdocument/Exe.cs index 0c8f7d89ae..32595ce9ab 100644 --- a/src/dotnet-getdocument/Exe.cs +++ b/src/dotnet-getdocument/Exe.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Text; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal static class Exe { diff --git a/src/dotnet-getdocument/Program.cs b/src/dotnet-getdocument/Program.cs index 495573a776..b93d3e1144 100644 --- a/src/dotnet-getdocument/Program.cs +++ b/src/dotnet-getdocument/Program.cs @@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using GetDocument.Commands; -using GetDocument.Properties; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Commands; +using Microsoft.Extensions.ApiDescription.Client.Properties; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal static class Program { diff --git a/src/dotnet-getdocument/Project.cs b/src/dotnet-getdocument/Project.cs index 274960a08b..b778838ed8 100644 --- a/src/dotnet-getdocument/Project.cs +++ b/src/dotnet-getdocument/Project.cs @@ -5,14 +5,14 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using GetDocument.Properties; +using Microsoft.Extensions.ApiDescription.Client.Properties; using IODirectory = System.IO.Directory; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal class Project { - private const string MSBuildResourceName = "GetDocument.ServiceProjectReferenceMetadata"; + private const string MSBuildResourceName = "Microsoft.Extensions.ApiDescription.Client.ServiceProjectReferenceMetadata"; private Project() { diff --git a/src/dotnet-getdocument/ProjectOptions.cs b/src/dotnet-getdocument/ProjectOptions.cs index bca160eeaa..59ddd4d48d 100644 --- a/src/dotnet-getdocument/ProjectOptions.cs +++ b/src/dotnet-getdocument/ProjectOptions.cs @@ -1,10 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using GetDocument.Properties; using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.Extensions.ApiDescription.Client.Properties; -namespace GetDocument +namespace Microsoft.Extensions.ApiDescription.Client { internal class ProjectOptions { diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.cs b/src/dotnet-getdocument/Properties/Resources.Designer.cs index 3ee7f0ba79..351107083c 100644 --- a/src/dotnet-getdocument/Properties/Resources.Designer.cs +++ b/src/dotnet-getdocument/Properties/Resources.Designer.cs @@ -5,7 +5,7 @@ using System.Reflection; using System.Resources; using JetBrains.Annotations; -namespace GetDocument.Properties +namespace Microsoft.Extensions.ApiDescription.Client.Properties { /// /// This API supports the GetDocument infrastructure and is not intended to be used @@ -14,7 +14,7 @@ namespace GetDocument.Properties internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("GetDocument.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); /// /// The configuration to use. @@ -23,7 +23,7 @@ namespace GetDocument.Properties => GetString("ConfigurationDescription"); /// - /// dotnet getdocument + /// dotnet-getdocument /// public static string CommandFullName => GetString("CommandFullName"); @@ -55,7 +55,7 @@ namespace GetDocument.Properties projectDirectory); /// - /// Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the GetDocument Command-line Tool only supports version 2.0 or higher. + /// Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher. /// public static string NETCoreApp1Project([CanBeNull] object Project, [CanBeNull] object targetFrameworkVersion) => string.Format( @@ -63,7 +63,7 @@ namespace GetDocument.Properties Project, targetFrameworkVersion); /// - /// Project '{Project}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the GetDocument Command-line Tool with this project, add an executable project targeting .NET Core or .NET Framework that references this project and specify it using the --project option; or, update this project to target .NET Core and / or .NET Framework. + /// Project '{Project}' 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. /// public static string NETStandardProject([CanBeNull] object Project) => string.Format( @@ -115,7 +115,7 @@ namespace GetDocument.Properties => GetString("RuntimeDescription"); /// - /// Project '{Project}' targets framework '{targetFramework}'. The GetDocument Command-line Tool does not support this framework. + /// Project '{Project}' targets framework '{targetFramework}'. The dotnet-getdocument tool does not support this framework. /// public static string UnsupportedFramework([CanBeNull] object Project, [CanBeNull] object targetFramework) => string.Format( diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.tt b/src/dotnet-getdocument/Properties/Resources.Designer.tt index 3f636a4db5..29bb487272 100644 --- a/src/dotnet-getdocument/Properties/Resources.Designer.tt +++ b/src/dotnet-getdocument/Properties/Resources.Designer.tt @@ -3,4 +3,4 @@ Session["AccessModifier"] = "internal"; Session["NoDiagnostics"] = true; #> -<#@ include file="..\..\tools\Resources.tt" #> +<#@ include file="..\..\..\tools\Resources.tt" #> diff --git a/src/dotnet-getdocument/Properties/Resources.resx b/src/dotnet-getdocument/Properties/Resources.resx index 16e16b8086..dc049de189 100644 --- a/src/dotnet-getdocument/Properties/Resources.resx +++ b/src/dotnet-getdocument/Properties/Resources.resx @@ -121,7 +121,7 @@ The configuration to use. - dotnet getdocument + dotnet-getdocument The target framework. @@ -136,10 +136,10 @@ More than one project was found in directory '{projectDirectory}'. Specify one using its file name. - Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the GetDocument Command-line Tool only supports version 2.0 or higher. + Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher. - Project '{Project}' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the GetDocument Command-line Tool with this project, add an executable project targeting .NET Core or .NET Framework that references this project and specify it using the --project option; or, update this project to target .NET Core and / or .NET Framework. + Project '{Project}' 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. Do not colorize output. @@ -163,7 +163,7 @@ The runtime identifier to use. - Project '{Project}' targets framework '{targetFramework}'. The GetDocument Command-line Tool does not support this framework. + Project '{Project}' targets framework '{targetFramework}'. The dotnet-getdocument tool does not support this framework. Using project '{project}'. diff --git a/src/dotnet-getdocument/dotnet-getdocument.csproj b/src/dotnet-getdocument/dotnet-getdocument.csproj index b88db8367a..73d57bffd9 100644 --- a/src/dotnet-getdocument/dotnet-getdocument.csproj +++ b/src/dotnet-getdocument/dotnet-getdocument.csproj @@ -16,7 +16,7 @@ Exe true GetDocument;command line;command-line;tool - GetDocument + Microsoft.Extensions.ApiDescription.Client netcoreapp2.1 diff --git a/tools/Resources.tt b/tools/Resources.tt new file mode 100644 index 0000000000..736a0cc442 --- /dev/null +++ b/tools/Resources.tt @@ -0,0 +1,226 @@ +<#@ template hostspecific="true" #> +<#@ assembly name="EnvDTE" #> +<#@ assembly name="System.Core" #> +<#@ assembly name="System.Windows.Forms" #> +<#@ import namespace="System.Collections" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.ComponentModel.Design" #> +<#@ import namespace="System.IO" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Resources" #> +<#@ import namespace="System.Text.RegularExpressions" #> +<#@ import namespace="EnvDTE" #> +<# + var model = LoadResources(); +#> +// + +using System; +using System.Reflection; +using System.Resources; +using JetBrains.Annotations; +<# + if (!model.NoDiagnostics) + { +#> +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Logging; +<# + } +#> + +namespace <#= model.Namespace #> +{ + /// + /// This API supports the GetDocument infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + <#= model.AccessModifier #> static class <#= model.Class #> + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("<#= model.ResourceName #>", typeof(<#= model.Class #>).GetTypeInfo().Assembly); +<# + foreach (var resource in model.Resources) + { +#> + + /// +<# + foreach (var line in Lines(resource.Value)) + { +#> + /// <#= Xml(line) #> +<# + } +#> + /// +<# + if (resource.ForLogging) + { + if (resource.Types.Count() > 6) + { +#> + public static readonly FallbackEventDefinition <#= resource.Name #> + = new FallbackEventDefinition( + <#= resource.EventId #>, + LogLevel.<#= resource.Level #>, + "<#= resource.EventId #>", + _resourceManager.GetString("<#= resource.Name #>")); +<# + } + else + { + var genericTypes = resource.Types.Any() ? ("<" + List(resource.Types) + ">") : ""; +#> + public static readonly EventDefinition<#= genericTypes #> <#= resource.Name #> + = new EventDefinition<#= genericTypes #>( + <#= resource.EventId #>, + LogLevel.<#= resource.Level #>, + "<#= resource.EventId #>", + LoggerMessage.Define<#= genericTypes #>( + LogLevel.<#= resource.Level #>, + <#= resource.EventId #>, + _resourceManager.GetString("<#= resource.Name #>"))); +<# + } + } + else + { + if (resource.Parameters.Any()) + { +#> + public static string <#= resource.Name #>(<#= List("[CanBeNull] object ", resource.Parameters) #>) + => string.Format( + GetString("<#= resource.Name #>", <#= List("nameof(", resource.Parameters, ")") #>), + <#= List(resource.Parameters) #>); +<# + } + else + { +#> + public static string <#= resource.Name #> + => GetString("<#= resource.Name #>"); +<# + } + } + } +#> + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + + return value; + } + } +} +<#+ + ResourceFile LoadResources() + { + var result = new ResourceFile(); + + if (Session.ContainsKey("AccessModifier")) + { + result.AccessModifier = (string)Session["AccessModifier"]; + }; + + var services = (IServiceProvider)Host; + var dte = (DTE)services.GetService(typeof(DTE)); + + if (!Session.TryGetValue("NoDiagnostics", out var noDiagnostics)) + { + noDiagnostics = false; + } + + result.NoDiagnostics = (bool)noDiagnostics; + + var resourceFile = (string)Session["ResourceFile"]; + if (!Path.IsPathRooted(resourceFile)) + { + resourceFile = Host.ResolvePath(resourceFile); + } + + var resourceProjectItem = dte.Solution.FindProjectItem(resourceFile); + var templateProjectItem = dte.Solution.FindProjectItem(Host.TemplateFile); + var project = templateProjectItem.ContainingProject; + var rootNamespace = (string)project.Properties.Item("RootNamespace").Value; + var resourceDir = Path.GetDirectoryName(resourceFile); + var projectDir = (string)project.Properties.Item("FullPath").Value; + var resourceNamespace = rootNamespace + "." + resourceDir.Substring(projectDir.Length) + .Replace(Path.DirectorySeparatorChar, '.'); + + result.Namespace = (string)resourceProjectItem.Properties.Item("CustomToolNamespace")?.Value; + if (string.IsNullOrEmpty(result.Namespace)) + { + result.Namespace = resourceNamespace; + } + + result.Class = Path.GetFileNameWithoutExtension(resourceFile); + + result.ResourceName = resourceNamespace + "." + result.Class; + + using (var reader = new ResXResourceReader(resourceFile)) + { + reader.UseResXDataNodes = true; + + result.Resources = Enumerable.ToList( + from DictionaryEntry r in reader + select new Resource((ResXDataNode)r.Value)); + } + + return result; + } + + IEnumerable Lines(string value) + => value.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + + string Xml(string value) + => value.Replace("<", "<").Replace(">", ">"); + + string List(IEnumerable items) + => List(null, items); + + string List(string prefix, IEnumerable items, string suffix = null) + => string.Join(", ", items.Select(i => prefix + i + suffix)); + + class ResourceFile + { + public string Namespace { get; set; } + public string AccessModifier { get; set; } = "public"; + public string Class { get; set; } + public string ResourceName { get; set; } + public IEnumerable Resources { get; set; } + public bool NoDiagnostics { get; set; } + } + + class Resource + { + public Resource(ResXDataNode node) + { + Name = node.Name; + Value = (string)node.GetValue((ITypeResolutionService)null); + Parameters = Regex.Matches(Value, @"\{(\w+)\}") + .Cast() + .Select(m => m.Groups[1].Value) + .Distinct() + .ToList(); + + var eventInfo = node.Comment.Split(' '); + Level = eventInfo.FirstOrDefault() ?? "BadLevel"; + EventId = eventInfo.Skip(1).FirstOrDefault() ?? "BadEventId"; + Types = eventInfo.Skip(2).ToList(); + } + + public string Name { get; } + public string Value { get; } + public string EventId { get; } + public string Level { get; } + public bool ForLogging => Name.StartsWith("Log"); + public IEnumerable Parameters { get; } + public IEnumerable Types { get; } + } +#> \ No newline at end of file From e19c036f1140b913e60970e1d65488b1bd67faa5 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 6 Sep 2018 12:03:23 -0700 Subject: [PATCH 03/14] Fix up MSBuild files - correct filenames - remove NSwag-specific files --- ...ft.Extensions.ApiDescription.Client.props} | 1 - ....Extensions.ApiDescription.Client.targets} | 1 - .../build/NSwagServiceReference.props | 20 --- .../build/NSwagServiceReference.targets | 131 ------------------ 4 files changed, 153 deletions(-) rename src/Microsoft.Extensions.ApiDescription.Client/build/{GenerationTasks.props => Microsoft.Extensions.ApiDescription.Client.props} (99%) rename src/Microsoft.Extensions.ApiDescription.Client/build/{GenerationTasks.targets => Microsoft.Extensions.ApiDescription.Client.targets} (99%) delete mode 100644 src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props delete mode 100644 src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props similarity index 99% rename from src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props rename to src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props index 989e7d9b23..45384b7d3e 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.props +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props @@ -1,6 +1,5 @@  - <_ApiDescriptionTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 <_ApiDescriptionTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' != 'Core'">net461 diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets similarity index 99% rename from src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets rename to src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets index 1b9b1ac184..6a68aba48b 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/GenerationTasks.targets +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets @@ -1,6 +1,5 @@  - diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props b/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props deleted file mode 100644 index 4269fdd11c..0000000000 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - - _NSwagDocumentGenerator_GetMetadata; - _NSwagDocumentGenerator_Core; - _NSwagDocumentGenerator_SetMetadata - - - _NSwagCSharpCodeGenerator_GetMetadata; - _NSwagCSharpCodeGenerator_Core; - _NSwagCSharpCodeGenerator_SetMetadata - - - _NSwagTypeScriptCodeGenerator_GetMetadata; - _NSwagTypeScriptCodeGenerator_Core; - _NSwagTypeScriptCodeGenerator_SetMetadata - - - diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets deleted file mode 100644 index e73cd8d641..0000000000 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/NSwagServiceReference.targets +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - <_NSwagTemporary Remove="@(_NSwagTemporary)" /> - <_NSwagTemporary Include="@(ServiceProjectReference -> WithMetadataValue('DocumentGenerator', 'NSwag'))"> - $(NSwagDocumentGeneratorDefaultOptions) - - - - - - - - <_Command>$(NSwagExe_Core21) aspnetcore2swagger /Configuration:$(Configuration) /NoBuild:true - - - - - - - <_Command /> - - - - - - - - - <_NSwagTemporary Remove="@(_NSwagTemporary)" /> - - - - - - - - - - <_NSwagTemporary Remove="@(_NSwagTemporary)" /> - <_NSwagTemporary Include="@(ServiceFileReference -> WithMetadataValue('CodeGenerator', 'NSwagCSharp'))"> - $(NSwagCSharpCodeGeneratorDefaultOptions) - - <_NSwagTemporary Update="@(_NSwagTemporary)"> - $(ServiceFileReferenceDirectory)%(ClassName).cs - - - - - - - <_Command>$(NSwagExe_Core21) swagger2csclient /namespace:$(NSwagCSharpCodeGeneratorNamespace) - - - - - - - <_Command /> - - - - - - - - - - - <_NSwagTemporary Remove="@(_NSwagTemporary)" /> - - - - - - - - - - <_NSwagTemporary Remove="@(_NSwagTemporary)" /> - <_NSwagTemporary Include="@(ServiceFileReference -> WithMetadataValue('CodeGenerator', 'NSwagTypeScript'))"> - $(NSwagTypeScriptCodeGeneratorDefaultOptions) - - <_NSwagTemporary Update="@(_NSwagTemporary)"> - $(ServiceFileReferenceDirectory)%(ClassName).ts - - - - - - - <_Command>$(NSwagExe_Core21) swagger2tsclient /namespace:$(NSwagTypeScriptCodeGeneratorNamespace) - - - - - - - <_Command /> - - - - - - - - - <_NSwagTemporary Remove="@(_NSwagTemporary)" /> - - - - - From 6ffcf3571e41dfb699d47e73ee4172e47737b52f Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 6 Sep 2018 11:39:50 -0700 Subject: [PATCH 04/14] Remove T4 custom tool - use same generator as most other projects in aspnet repos - were not using named arguments to resource methods anyhow - update resources to use regular (numbered) format parameters - adjust to new `Resources` namespace; no need for separate `using` - use `Format...(...)` methods as necessary --- .../Commands/CommandBase.cs | 1 - .../Commands/GetDocumentCommand.cs | 13 +- .../Commands/GetDocumentCommandWorker.cs | 13 +- .../Commands/ProjectCommandBase.cs | 5 +- .../GetDocumentInsider.csproj | 19 - src/GetDocumentInsider/Json.cs | 1 - .../Properties/Resources.Designer.cs | 381 +++++++++++++----- .../Properties/Resources.Designer.tt | 6 - .../{Properties => }/Resources.resx | 34 +- .../Commands/InvokeCommand.cs | 13 +- src/dotnet-getdocument/Program.cs | 1 - src/dotnet-getdocument/Project.cs | 11 +- src/dotnet-getdocument/ProjectOptions.cs | 1 - .../Properties/Resources.Designer.cs | 325 +++++++++++---- .../Properties/Resources.Designer.tt | 6 - .../{Properties => }/Resources.resx | 72 ++-- .../dotnet-getdocument.csproj | 19 - tools/Resources.tt | 226 ----------- 18 files changed, 590 insertions(+), 557 deletions(-) delete mode 100644 src/GetDocumentInsider/Properties/Resources.Designer.tt rename src/GetDocumentInsider/{Properties => }/Resources.resx (89%) delete mode 100644 src/dotnet-getdocument/Properties/Resources.Designer.tt rename src/dotnet-getdocument/{Properties => }/Resources.resx (83%) delete mode 100644 tools/Resources.tt diff --git a/src/GetDocumentInsider/Commands/CommandBase.cs b/src/GetDocumentInsider/Commands/CommandBase.cs index 61e83151ce..5ca14744cb 100644 --- a/src/GetDocumentInsider/Commands/CommandBase.cs +++ b/src/GetDocumentInsider/Commands/CommandBase.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Properties; namespace Microsoft.Extensions.ApiDescription.Client.Commands { diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs index af61b02af6..583031b324 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs @@ -9,7 +9,6 @@ using System.Reflection; using System.Runtime.Loader; #endif using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Properties; namespace Microsoft.Extensions.ApiDescription.Client.Commands { @@ -32,10 +31,10 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands _documentName = command.Option( "--documentName ", - Resources.DocumentDescription(FallbackDocumentName)); - _method = command.Option("--method ", Resources.MethodDescription(FallbackMethod)); + Resources.FormatDocumentDescription(FallbackDocumentName)); + _method = command.Option("--method ", Resources.FormatMethodDescription(FallbackMethod)); _output = command.Option("--output ", Resources.OutputDescription); - _service = command.Option("--service ", Resources.ServiceDescription(FallbackService)); + _service = command.Option("--service ", Resources.FormatServiceDescription(FallbackService)); _uri = command.Option("--uri ", Resources.UriDescription); } @@ -45,17 +44,17 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands if (!_output.HasValue()) { - throw new CommandException(Resources.MissingOption(_output.LongName)); + throw new CommandException(Resources.FormatMissingOption(_output.LongName)); } if (_method.HasValue() && !_service.HasValue()) { - throw new CommandException(Resources.MissingOption(_service.LongName)); + throw new CommandException(Resources.FormatMissingOption(_service.LongName)); } if (_service.HasValue() && !_method.HasValue()) { - throw new CommandException(Resources.MissingOption(_method.LongName)); + throw new CommandException(Resources.FormatMissingOption(_method.LongName)); } } diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs index 97a1f4e809..58d562ef2d 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.ApiDescription.Client.Properties; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -21,7 +20,7 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands var entryPointType = assembly.EntryPoint?.DeclaringType; if (entryPointType == null) { - Reporter.WriteError(Resources.MissingEntryPoint(context.AssemblyPath)); + Reporter.WriteError(Resources.FormatMissingEntryPoint(context.AssemblyPath)); return 2; } @@ -68,9 +67,9 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands GetDocumentCommand.FallbackService : context.Service; - Reporter.WriteInformation(Resources.UsingDocument(documentName)); - Reporter.WriteInformation(Resources.UsingMethod(methodName)); - Reporter.WriteInformation(Resources.UsingService(serviceName)); + Reporter.WriteInformation(Resources.FormatUsingDocument(documentName)); + Reporter.WriteInformation(Resources.FormatUsingMethod(methodName)); + Reporter.WriteInformation(Resources.FormatUsingService(serviceName)); try { @@ -93,7 +92,7 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands if (!success) { - var message = Resources.MethodInvocationFailed(methodName, serviceName, documentName); + var message = Resources.FormatMethodInvocationFailed(methodName, serviceName, documentName); if (string.IsNullOrEmpty(context.Uri) && !File.Exists(context.Output)) { Reporter.WriteError(message); @@ -126,7 +125,7 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands { Debug.Assert(!string.IsNullOrEmpty(context.Uri)); - Reporter.WriteInformation(Resources.UsingUri(context.Uri)); + Reporter.WriteInformation(Resources.FormatUsingUri(context.Uri)); var httpClient = server.CreateClient(); await DownloadFileCore.DownloadAsync( diff --git a/src/GetDocumentInsider/Commands/ProjectCommandBase.cs b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs index 71e74947d0..7e6e49c750 100644 --- a/src/GetDocumentInsider/Commands/ProjectCommandBase.cs +++ b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Properties; namespace Microsoft.Extensions.ApiDescription.Client.Commands { @@ -26,12 +25,12 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands if (!AssemblyPath.HasValue()) { - throw new CommandException(Resources.MissingOption(AssemblyPath.LongName)); + throw new CommandException(Resources.FormatMissingOption(AssemblyPath.LongName)); } if (!ToolsDirectory.HasValue()) { - throw new CommandException(Resources.MissingOption(ToolsDirectory.LongName)); + throw new CommandException(Resources.FormatMissingOption(ToolsDirectory.LongName)); } } } diff --git a/src/GetDocumentInsider/GetDocumentInsider.csproj b/src/GetDocumentInsider/GetDocumentInsider.csproj index abd288edd7..48de9b92d4 100644 --- a/src/GetDocumentInsider/GetDocumentInsider.csproj +++ b/src/GetDocumentInsider/GetDocumentInsider.csproj @@ -17,23 +17,4 @@ - - - - TextTemplatingFileGenerator - Resources.Designer.cs - - - - - - - - - - True - True - Resources.Designer.tt - - diff --git a/src/GetDocumentInsider/Json.cs b/src/GetDocumentInsider/Json.cs index 7e93ac21cd..53885c5825 100644 --- a/src/GetDocumentInsider/Json.cs +++ b/src/GetDocumentInsider/Json.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Properties; namespace Microsoft.Extensions.ApiDescription.Client { diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.cs b/src/GetDocumentInsider/Properties/Resources.Designer.cs index 7f3066776c..460ca76235 100644 --- a/src/GetDocumentInsider/Properties/Resources.Designer.cs +++ b/src/GetDocumentInsider/Properties/Resources.Designer.cs @@ -1,207 +1,366 @@ // - -using System; -using System.Reflection; -using System.Resources; -using JetBrains.Annotations; - -namespace Microsoft.Extensions.ApiDescription.Client.Properties +namespace Microsoft.Extensions.ApiDescription.Client { - /// - /// This API supports the GetDocument infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// + using System.Globalization; + using System.Reflection; + using System.Resources; + internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Resources", typeof(Resources).GetTypeInfo().Assembly); /// - /// The assembly to use. + /// The assembly to use. /// - public static string AssemblyDescription + internal static string AssemblyDescription + { + get => GetString("AssemblyDescription"); + } + + /// + /// The assembly to use. + /// + internal static string FormatAssemblyDescription() => GetString("AssemblyDescription"); /// - /// Show JSON output. + /// Show JSON output. /// - public static string JsonDescription + internal static string JsonDescription + { + get => GetString("JsonDescription"); + } + + /// + /// Show JSON output. + /// + internal static string FormatJsonDescription() => GetString("JsonDescription"); /// - /// Missing required option '--{option}'. + /// Missing required option '--{0}'. /// - public static string MissingOption([CanBeNull] object option) - => string.Format( - GetString("MissingOption", nameof(option)), - option); + internal static string MissingOption + { + get => GetString("MissingOption"); + } /// - /// Do not colorize output. + /// Missing required option '--{0}'. /// - public static string NoColorDescription + internal static string FormatMissingOption(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("MissingOption"), p0); + + /// + /// Do not colorize output. + /// + internal static string NoColorDescription + { + get => GetString("NoColorDescription"); + } + + /// + /// Do not colorize output. + /// + internal static string FormatNoColorDescription() => GetString("NoColorDescription"); /// - /// The file to write the result to. + /// The file to write the result to. /// - public static string OutputDescription + internal static string OutputDescription + { + get => GetString("OutputDescription"); + } + + /// + /// The file to write the result to. + /// + internal static string FormatOutputDescription() => GetString("OutputDescription"); /// - /// Prefix console output with logging level. + /// Prefix console output with logging level. /// - public static string PrefixDescription + internal static string PrefixDescription + { + get => GetString("PrefixDescription"); + } + + /// + /// Prefix console output with logging level. + /// + internal static string FormatPrefixDescription() => GetString("PrefixDescription"); /// - /// Using application base '{appBase}'. + /// Using application base '{0}'. /// - public static string UsingApplicationBase([CanBeNull] object appBase) - => string.Format( - GetString("UsingApplicationBase", nameof(appBase)), - appBase); + internal static string UsingApplicationBase + { + get => GetString("UsingApplicationBase"); + } /// - /// Using assembly '{assembly}'. + /// Using application base '{0}'. /// - public static string UsingAssembly([CanBeNull] object assembly) - => string.Format( - GetString("UsingAssembly", nameof(assembly)), - assembly); + internal static string FormatUsingApplicationBase(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingApplicationBase"), p0); /// - /// Using configuration file '{config}'. + /// Using assembly '{0}'. /// - public static string UsingConfigurationFile([CanBeNull] object config) - => string.Format( - GetString("UsingConfigurationFile", nameof(config)), - config); + internal static string UsingAssembly + { + get => GetString("UsingAssembly"); + } /// - /// Show verbose output. + /// Using assembly '{0}'. /// - public static string VerboseDescription + internal static string FormatUsingAssembly(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingAssembly"), p0); + + /// + /// Using configuration file '{0}'. + /// + internal static string UsingConfigurationFile + { + get => GetString("UsingConfigurationFile"); + } + + /// + /// Using configuration file '{0}'. + /// + internal static string FormatUsingConfigurationFile(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingConfigurationFile"), p0); + + /// + /// Show verbose output. + /// + internal static string VerboseDescription + { + get => GetString("VerboseDescription"); + } + + /// + /// Show verbose output. + /// + internal static string FormatVerboseDescription() => GetString("VerboseDescription"); /// - /// Writing '{file}'... + /// Writing '{0}'... /// - public static string WritingFile([CanBeNull] object file) - => string.Format( - GetString("WritingFile", nameof(file)), - file); + internal static string WritingFile + { + get => GetString("WritingFile"); + } /// - /// Using working directory '{workingDirectory}'. + /// Writing '{0}'... /// - public static string UsingWorkingDirectory([CanBeNull] object workingDirectory) - => string.Format( - GetString("UsingWorkingDirectory", nameof(workingDirectory)), - workingDirectory); + internal static string FormatWritingFile(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("WritingFile"), p0); /// - /// Location from which inside man was copied (in the .NET Framework case) or loaded. + /// Using working directory '{0}'. /// - public static string ToolsDirectoryDescription + internal static string UsingWorkingDirectory + { + get => GetString("UsingWorkingDirectory"); + } + + /// + /// Using working directory '{0}'. + /// + internal static string FormatUsingWorkingDirectory(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingWorkingDirectory"), p0); + + /// + /// Location from which inside man was copied (in the .NET Framework case) or loaded. + /// + internal static string ToolsDirectoryDescription + { + get => GetString("ToolsDirectoryDescription"); + } + + /// + /// Location from which inside man was copied (in the .NET Framework case) or loaded. + /// + internal static string FormatToolsDirectoryDescription() => GetString("ToolsDirectoryDescription"); /// - /// The URI to download the document from. + /// The URI to download the document from. /// - public static string UriDescription + internal static string UriDescription + { + get => GetString("UriDescription"); + } + + /// + /// The URI to download the document from. + /// + internal static string FormatUriDescription() => GetString("UriDescription"); /// - /// The name of the method to invoke on the '--service' instance. Default value '{defaultMethod}'. + /// The name of the method to invoke on the '--service' instance. Default value '{0}'. /// - public static string MethodDescription([CanBeNull] object defaultMethod) - => string.Format( - GetString("MethodDescription", nameof(defaultMethod)), - defaultMethod); + internal static string MethodDescription + { + get => GetString("MethodDescription"); + } /// - /// The qualified name of the service type to retrieve from dependency injection. Default value '{defaultService}'. + /// The name of the method to invoke on the '--service' instance. Default value '{0}'. /// - public static string ServiceDescription([CanBeNull] object defaultService) - => string.Format( - GetString("ServiceDescription", nameof(defaultService)), - defaultService); + internal static string FormatMethodDescription(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("MethodDescription"), p0); /// - /// Missing required option '--{option1}' or '--{option2}'. + /// The qualified name of the service type to retrieve from dependency injection. Default value '{0}'. /// - public static string MissingOptions([CanBeNull] object option1, [CanBeNull] object option2) - => string.Format( - GetString("MissingOptions", nameof(option1), nameof(option2)), - option1, option2); + internal static string ServiceDescription + { + get => GetString("ServiceDescription"); + } /// - /// The name of the document to pass to the '--method' method. Default value '{defaultDocumentName}'. + /// The qualified name of the service type to retrieve from dependency injection. Default value '{0}'. /// - public static string DocumentDescription([CanBeNull] object defaultDocumentName) - => string.Format( - GetString("DocumentDescription", nameof(defaultDocumentName)), - defaultDocumentName); + internal static string FormatServiceDescription(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("ServiceDescription"), p0); /// - /// Using document name '{documentName}'. + /// Missing required option '--{0}' or '--{1}'. /// - public static string UsingDocument([CanBeNull] object documentName) - => string.Format( - GetString("UsingDocument", nameof(documentName)), - documentName); + internal static string MissingOptions + { + get => GetString("MissingOptions"); + } /// - /// Using method '{method}'. + /// Missing required option '--{0}' or '--{1}'. /// - public static string UsingMethod([CanBeNull] object method) - => string.Format( - GetString("UsingMethod", nameof(method)), - method); + internal static string FormatMissingOptions(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("MissingOptions"), p0, p1); /// - /// Using service '{service}'. + /// The name of the document to pass to the '--method' method. Default value '{0}'. /// - public static string UsingService([CanBeNull] object service) - => string.Format( - GetString("UsingService", nameof(service)), - service); + internal static string DocumentDescription + { + get => GetString("DocumentDescription"); + } /// - /// Using URI '{uri}'. + /// The name of the document to pass to the '--method' method. Default value '{0}'. /// - public static string UsingUri([CanBeNull] object uri) - => string.Format( - GetString("UsingUri", nameof(uri)), - uri); + internal static string FormatDocumentDescription(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("DocumentDescription"), p0); /// - /// Method '{method}' of service '{service}' failed to generate document '{documentName}'. + /// Using document name '{0}'. /// - public static string MethodInvocationFailed([CanBeNull] object method, [CanBeNull] object service, [CanBeNull] object documentName) - => string.Format( - GetString("MethodInvocationFailed", nameof(method), nameof(service), nameof(documentName)), - method, service, documentName); + internal static string UsingDocument + { + get => GetString("UsingDocument"); + } /// - /// Assembly '{assemblyPath}' does not contain an entry point. + /// Using document name '{0}'. /// - public static string MissingEntryPoint([CanBeNull] object assemblyPath) - => string.Format( - GetString("MissingEntryPoint", nameof(assemblyPath)), - assemblyPath); + internal static string FormatUsingDocument(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingDocument"), p0); + + /// + /// Using method '{0}'. + /// + internal static string UsingMethod + { + get => GetString("UsingMethod"); + } + + /// + /// Using method '{0}'. + /// + internal static string FormatUsingMethod(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingMethod"), p0); + + /// + /// Using service '{0}'. + /// + internal static string UsingService + { + get => GetString("UsingService"); + } + + /// + /// Using service '{0}'. + /// + internal static string FormatUsingService(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingService"), p0); + + /// + /// Using URI '{0}'. + /// + internal static string UsingUri + { + get => GetString("UsingUri"); + } + + /// + /// Using URI '{0}'. + /// + internal static string FormatUsingUri(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingUri"), p0); + + /// + /// Method '{0}' of service '{1}' failed to generate document '{2}'. + /// + internal static string MethodInvocationFailed + { + get => GetString("MethodInvocationFailed"); + } + + /// + /// Method '{0}' of service '{1}' failed to generate document '{2}'. + /// + internal static string FormatMethodInvocationFailed(object p0, object p1, object p2) + => string.Format(CultureInfo.CurrentCulture, GetString("MethodInvocationFailed"), p0, p1, p2); + + /// + /// Assembly '{0}' does not contain an entry point. + /// + internal static string MissingEntryPoint + { + get => GetString("MissingEntryPoint"); + } + + /// + /// Assembly '{0}' does not contain an entry point. + /// + 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); - for (var i = 0; i < formatterNames.Length; i++) + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) { - value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } } return value; } } } - diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.tt b/src/GetDocumentInsider/Properties/Resources.Designer.tt deleted file mode 100644 index 29bb487272..0000000000 --- a/src/GetDocumentInsider/Properties/Resources.Designer.tt +++ /dev/null @@ -1,6 +0,0 @@ -<# - Session["ResourceFile"] = "Resources.resx"; - Session["AccessModifier"] = "internal"; - Session["NoDiagnostics"] = true; -#> -<#@ include file="..\..\..\tools\Resources.tt" #> diff --git a/src/GetDocumentInsider/Properties/Resources.resx b/src/GetDocumentInsider/Resources.resx similarity index 89% rename from src/GetDocumentInsider/Properties/Resources.resx rename to src/GetDocumentInsider/Resources.resx index f5c08e3a40..f42b6144e6 100644 --- a/src/GetDocumentInsider/Properties/Resources.resx +++ b/src/GetDocumentInsider/Resources.resx @@ -124,7 +124,7 @@ Show JSON output. - Missing required option '--{option}'. + Missing required option '--{0}'. Do not colorize output. @@ -136,22 +136,22 @@ Prefix console output with logging level. - Using application base '{appBase}'. + Using application base '{0}'. - Using assembly '{assembly}'. + Using assembly '{0}'. - Using configuration file '{config}'. + Using configuration file '{0}'. Show verbose output. - Writing '{file}'... + Writing '{0}'... - Using working directory '{workingDirectory}'. + Using working directory '{0}'. Location from which inside man was copied (in the .NET Framework case) or loaded. @@ -160,33 +160,33 @@ The URI to download the document from. - The name of the method to invoke on the '--service' instance. Default value '{defaultMethod}'. + The name of the method to invoke on the '--service' instance. Default value '{0}'. - The qualified name of the service type to retrieve from dependency injection. Default value '{defaultService}'. + The qualified name of the service type to retrieve from dependency injection. Default value '{0}'. - Missing required option '--{option1}' or '--{option2}'. + Missing required option '--{0}' or '--{1}'. - The name of the document to pass to the '--method' method. Default value '{defaultDocumentName}'. + The name of the document to pass to the '--method' method. Default value '{0}'. - Using document name '{documentName}'. + Using document name '{0}'. - Using method '{method}'. + Using method '{0}'. - Using service '{service}'. + Using service '{0}'. - Using URI '{uri}'. + Using URI '{0}'. - Method '{method}' of service '{service}' failed to generate document '{documentName}'. + Method '{0}' of service '{1}' failed to generate document '{2}'. - Assembly '{assemblyPath}' does not contain an entry point. + Assembly '{0}' does not contain an entry point. - \ No newline at end of file + diff --git a/src/dotnet-getdocument/Commands/InvokeCommand.cs b/src/dotnet-getdocument/Commands/InvokeCommand.cs index f28aafacf4..b376b3b9d2 100644 --- a/src/dotnet-getdocument/Commands/InvokeCommand.cs +++ b/src/dotnet-getdocument/Commands/InvokeCommand.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using System.Runtime.Versioning; using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Properties; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -49,7 +48,7 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands _project.Value(), Resources.NoProject, Resources.MultipleProjects); - Reporter.WriteVerbose(Resources.UsingProject(projectFile)); + Reporter.WriteVerbose(Resources.FormatUsingProject(projectFile)); var project = Project.FromFile( projectFile, @@ -96,7 +95,7 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands if (targetFramework.Version < new Version(2, 0)) { throw new CommandException( - Resources.NETCoreApp1Project(project.Name, targetFramework.Version)); + Resources.FormatNETCoreApp1Project(project.Name, targetFramework.Version)); } args.Add("exec"); @@ -135,11 +134,11 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands break; case ".NETStandard": - throw new CommandException(Resources.NETStandardProject(project.Name)); + throw new CommandException(Resources.FormatNETStandardProject(project.Name)); default: throw new CommandException( - Resources.UnsupportedFramework(project.Name, targetFramework.Identifier)); + Resources.FormatUnsupportedFramework(project.Name, targetFramework.Identifier)); } args.AddRange(_args); @@ -224,14 +223,14 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands { throw new CommandException( specified - ? Resources.NoProjectInDirectory(path) + ? Resources.FormatNoProjectInDirectory(path) : errorWhenNoProject); } if (projectFiles.Count != 1) { throw new CommandException( specified - ? Resources.MultipleProjectsInDirectory(path) + ? Resources.FormatMultipleProjectsInDirectory(path) : errorWhenMultipleProjects); } diff --git a/src/dotnet-getdocument/Program.cs b/src/dotnet-getdocument/Program.cs index b93d3e1144..4e1f7fb5ca 100644 --- a/src/dotnet-getdocument/Program.cs +++ b/src/dotnet-getdocument/Program.cs @@ -4,7 +4,6 @@ using System; using Microsoft.DotNet.Cli.CommandLine; using Microsoft.Extensions.ApiDescription.Client.Commands; -using Microsoft.Extensions.ApiDescription.Client.Properties; namespace Microsoft.Extensions.ApiDescription.Client { diff --git a/src/dotnet-getdocument/Project.cs b/src/dotnet-getdocument/Project.cs index b778838ed8..ce3325b7e8 100644 --- a/src/dotnet-getdocument/Project.cs +++ b/src/dotnet-getdocument/Project.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using Microsoft.Extensions.ApiDescription.Client.Properties; using IODirectory = System.IO.Directory; namespace Microsoft.Extensions.ApiDescription.Client @@ -82,7 +81,7 @@ namespace Microsoft.Extensions.ApiDescription.Client { using (var output = File.OpenWrite(propsPath)) { - Reporter.WriteVerbose(Resources.WritingFile(propsPath)); + Reporter.WriteVerbose(Resources.FormatWritingFile(propsPath)); input.CopyTo(output); } } @@ -93,7 +92,7 @@ namespace Microsoft.Extensions.ApiDescription.Client using (var output = File.OpenWrite(targetsPath)) { // NB: Copy always in case it changes - Reporter.WriteVerbose(Resources.WritingFile(targetsPath)); + Reporter.WriteVerbose(Resources.FormatWritingFile(targetsPath)); input.CopyTo(output); } } @@ -171,17 +170,17 @@ namespace Microsoft.Extensions.ApiDescription.Client if (string.IsNullOrEmpty(project.AssemblyPath)) { - throw new CommandException(Resources.GetMetadataValueFailed(nameof(AssemblyPath), "TargetPath")); + throw new CommandException(Resources.FormatGetMetadataValueFailed(nameof(AssemblyPath), "TargetPath")); } if (string.IsNullOrEmpty(project.Directory)) { - throw new CommandException(Resources.GetMetadataValueFailed(nameof(Directory), "ProjectDir")); + throw new CommandException(Resources.FormatGetMetadataValueFailed(nameof(Directory), "ProjectDir")); } if (string.IsNullOrEmpty(project.OutputPath)) { - throw new CommandException(Resources.GetMetadataValueFailed(nameof(OutputPath), "OutDir")); + throw new CommandException(Resources.FormatGetMetadataValueFailed(nameof(OutputPath), "OutDir")); } if (!Path.IsPathRooted(project.Directory)) diff --git a/src/dotnet-getdocument/ProjectOptions.cs b/src/dotnet-getdocument/ProjectOptions.cs index 59ddd4d48d..f3b7d1148e 100644 --- a/src/dotnet-getdocument/ProjectOptions.cs +++ b/src/dotnet-getdocument/ProjectOptions.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Properties; namespace Microsoft.Extensions.ApiDescription.Client { diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.cs b/src/dotnet-getdocument/Properties/Resources.Designer.cs index 351107083c..eb38ce67a7 100644 --- a/src/dotnet-getdocument/Properties/Resources.Designer.cs +++ b/src/dotnet-getdocument/Properties/Resources.Designer.cs @@ -1,179 +1,338 @@ // - -using System; -using System.Reflection; -using System.Resources; -using JetBrains.Annotations; - -namespace Microsoft.Extensions.ApiDescription.Client.Properties +namespace Microsoft.Extensions.ApiDescription.Client { - /// - /// This API supports the GetDocument infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// + using System.Globalization; + using System.Reflection; + using System.Resources; + internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Resources", typeof(Resources).GetTypeInfo().Assembly); /// - /// The configuration to use. + /// The configuration to use. /// - public static string ConfigurationDescription + internal static string ConfigurationDescription + { + get => GetString("ConfigurationDescription"); + } + + /// + /// The configuration to use. + /// + internal static string FormatConfigurationDescription() => GetString("ConfigurationDescription"); /// - /// dotnet-getdocument + /// dotnet-getdocument /// - public static string CommandFullName + internal static string CommandFullName + { + get => GetString("CommandFullName"); + } + + /// + /// dotnet-getdocument + /// + internal static string FormatCommandFullName() => GetString("CommandFullName"); /// - /// The target framework. + /// The target framework. /// - public static string FrameworkDescription + internal static string FrameworkDescription + { + get => GetString("FrameworkDescription"); + } + + /// + /// The target framework. + /// + internal static string FormatFrameworkDescription() => GetString("FrameworkDescription"); /// - /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. + /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. /// - public static string GetMetadataFailed + internal static string GetMetadataFailed + { + get => GetString("GetMetadataFailed"); + } + + /// + /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. + /// + internal static string FormatGetMetadataFailed() => GetString("GetMetadataFailed"); /// - /// More than one project was found in the current working directory. Use the --project option. + /// More than one project was found in the current working directory. Use the --project option. /// - public static string MultipleProjects + internal static string MultipleProjects + { + get => GetString("MultipleProjects"); + } + + /// + /// More than one project was found in the current working directory. Use the --project option. + /// + internal static string FormatMultipleProjects() => GetString("MultipleProjects"); /// - /// More than one project was found in directory '{projectDirectory}'. Specify one using its file name. + /// More than one project was found in directory '{0}'. Specify one using its file name. /// - public static string MultipleProjectsInDirectory([CanBeNull] object projectDirectory) - => string.Format( - GetString("MultipleProjectsInDirectory", nameof(projectDirectory)), - projectDirectory); + internal static string MultipleProjectsInDirectory + { + get => GetString("MultipleProjectsInDirectory"); + } /// - /// Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher. + /// More than one project was found in directory '{0}'. Specify one using its file name. /// - public static string NETCoreApp1Project([CanBeNull] object Project, [CanBeNull] object targetFrameworkVersion) - => string.Format( - GetString("NETCoreApp1Project", nameof(Project), nameof(targetFrameworkVersion)), - Project, targetFrameworkVersion); + internal static string FormatMultipleProjectsInDirectory(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("MultipleProjectsInDirectory"), p0); /// - /// Project '{Project}' 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. + /// Project '{0}' targets framework '.NETCoreApp' version '{1}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher. /// - public static string NETStandardProject([CanBeNull] object Project) - => string.Format( - GetString("NETStandardProject", nameof(Project)), - Project); + internal static string NETCoreApp1Project + { + get => GetString("NETCoreApp1Project"); + } /// - /// Do not colorize output. + /// Project '{0}' targets framework '.NETCoreApp' version '{1}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher. /// - public static string NoColorDescription + internal static string FormatNETCoreApp1Project(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("NETCoreApp1Project"), p0, p1); + + /// + /// 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. + /// + internal static string NETStandardProject + { + get => GetString("NETStandardProject"); + } + + /// + /// 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. + /// + internal static string FormatNETStandardProject(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("NETStandardProject"), p0); + + /// + /// Do not colorize output. + /// + internal static string NoColorDescription + { + get => GetString("NoColorDescription"); + } + + /// + /// Do not colorize output. + /// + internal static string FormatNoColorDescription() => GetString("NoColorDescription"); /// - /// No project was found. Change the current working directory or use the --project option. + /// No project was found. Change the current working directory or use the --project option. /// - public static string NoProject + internal static string NoProject + { + get => GetString("NoProject"); + } + + /// + /// No project was found. Change the current working directory or use the --project option. + /// + internal static string FormatNoProject() => GetString("NoProject"); /// - /// No project was found in directory '{projectDirectory}'. + /// No project was found in directory '{0}'. /// - public static string NoProjectInDirectory([CanBeNull] object projectDirectory) - => string.Format( - GetString("NoProjectInDirectory", nameof(projectDirectory)), - projectDirectory); + internal static string NoProjectInDirectory + { + get => GetString("NoProjectInDirectory"); + } /// - /// Prefix output with level. + /// No project was found in directory '{0}'. /// - public static string PrefixDescription + internal static string FormatNoProjectInDirectory(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("NoProjectInDirectory"), p0); + + /// + /// Prefix output with level. + /// + internal static string PrefixDescription + { + get => GetString("PrefixDescription"); + } + + /// + /// Prefix output with level. + /// + internal static string FormatPrefixDescription() => GetString("PrefixDescription"); /// - /// The project to use. + /// The project to use. /// - public static string ProjectDescription + internal static string ProjectDescription + { + get => GetString("ProjectDescription"); + } + + /// + /// The project to use. + /// + internal static string FormatProjectDescription() => GetString("ProjectDescription"); /// - /// The MSBuild project extensions path. Defaults to "obj". + /// The MSBuild project extensions path. Defaults to "obj". /// - public static string ProjectExtensionsDescription + internal static string ProjectExtensionsDescription + { + get => GetString("ProjectExtensionsDescription"); + } + + /// + /// The MSBuild project extensions path. Defaults to "obj". + /// + internal static string FormatProjectExtensionsDescription() => GetString("ProjectExtensionsDescription"); /// - /// The runtime identifier to use. + /// The runtime identifier to use. /// - public static string RuntimeDescription + internal static string RuntimeDescription + { + get => GetString("RuntimeDescription"); + } + + /// + /// The runtime identifier to use. + /// + internal static string FormatRuntimeDescription() => GetString("RuntimeDescription"); /// - /// Project '{Project}' targets framework '{targetFramework}'. The dotnet-getdocument tool does not support this framework. + /// Project '{0}' targets framework '{1}'. The dotnet-getdocument tool does not support this framework. /// - public static string UnsupportedFramework([CanBeNull] object Project, [CanBeNull] object targetFramework) - => string.Format( - GetString("UnsupportedFramework", nameof(Project), nameof(targetFramework)), - Project, targetFramework); + internal static string UnsupportedFramework + { + get => GetString("UnsupportedFramework"); + } /// - /// Using project '{project}'. + /// Project '{0}' targets framework '{1}'. The dotnet-getdocument tool does not support this framework. /// - public static string UsingProject([CanBeNull] object project) - => string.Format( - GetString("UsingProject", nameof(project)), - project); + internal static string FormatUnsupportedFramework(object p0, object p1) + => string.Format(CultureInfo.CurrentCulture, GetString("UnsupportedFramework"), p0, p1); /// - /// Show verbose output. + /// Using project '{0}'. /// - public static string VerboseDescription + internal static string UsingProject + { + get => GetString("UsingProject"); + } + + /// + /// Using project '{0}'. + /// + internal static string FormatUsingProject(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("UsingProject"), p0); + + /// + /// Show verbose output. + /// + internal static string VerboseDescription + { + get => GetString("VerboseDescription"); + } + + /// + /// Show verbose output. + /// + internal static string FormatVerboseDescription() => GetString("VerboseDescription"); /// - /// Writing '{file}'... + /// Writing '{0}'... /// - public static string WritingFile([CanBeNull] object file) - => string.Format( - GetString("WritingFile", nameof(file)), - file); + internal static string WritingFile + { + get => GetString("WritingFile"); + } /// - /// Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + /// Writing '{0}'... /// - public static string MustBuild + internal static string FormatWritingFile(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("WritingFile"), p0); + + /// + /// Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + /// + internal static string MustBuild + { + get => GetString("MustBuild"); + } + + /// + /// Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + /// + internal static string FormatMustBuild() => GetString("MustBuild"); /// - /// The file to write the result to. + /// The file to write the result to. /// - public static string OutputDescription + internal static string OutputDescription + { + get => GetString("OutputDescription"); + } + + /// + /// The file to write the result to. + /// + internal static string FormatOutputDescription() => GetString("OutputDescription"); /// - /// Unable to retrieve '{properrty}' project metadata. Ensure '{msbuildProperty}' is set. + /// Unable to retrieve '{0}' project metadata. Ensure '{1}' is set. /// - public static string GetMetadataValueFailed([CanBeNull] object properrty, [CanBeNull] object msbuildProperty) - => string.Format( - GetString("GetMetadataValueFailed", nameof(properrty), nameof(msbuildProperty)), - properrty, msbuildProperty); + internal static string GetMetadataValueFailed + { + get => GetString("GetMetadataValueFailed"); + } + + /// + /// Unable to retrieve '{0}' project metadata. Ensure '{1}' is set. + /// + 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); - for (var i = 0; i < formatterNames.Length; i++) + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) { - value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } } return value; } } } - diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.tt b/src/dotnet-getdocument/Properties/Resources.Designer.tt deleted file mode 100644 index 29bb487272..0000000000 --- a/src/dotnet-getdocument/Properties/Resources.Designer.tt +++ /dev/null @@ -1,6 +0,0 @@ -<# - Session["ResourceFile"] = "Resources.resx"; - Session["AccessModifier"] = "internal"; - Session["NoDiagnostics"] = true; -#> -<#@ include file="..\..\..\tools\Resources.tt" #> diff --git a/src/dotnet-getdocument/Properties/Resources.resx b/src/dotnet-getdocument/Resources.resx similarity index 83% rename from src/dotnet-getdocument/Properties/Resources.resx rename to src/dotnet-getdocument/Resources.resx index dc049de189..7db5873e7d 100644 --- a/src/dotnet-getdocument/Properties/Resources.resx +++ b/src/dotnet-getdocument/Resources.resx @@ -1,17 +1,17 @@  - @@ -133,13 +133,13 @@ More than one project was found in the current working directory. Use the --project option. - More than one project was found in directory '{projectDirectory}'. Specify one using its file name. + More than one project was found in directory '{0}'. Specify one using its file name. - Project '{Project}' targets framework '.NETCoreApp' version '{targetFrameworkVersion}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher. + Project '{0}' targets framework '.NETCoreApp' version '{1}'. This version of the dotnet-getdocument tool only supports version 2.0 or higher. - Project '{Project}' 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. + 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. Do not colorize output. @@ -148,7 +148,7 @@ No project was found. Change the current working directory or use the --project option. - No project was found in directory '{projectDirectory}'. + No project was found in directory '{0}'. Prefix output with level. @@ -163,16 +163,16 @@ The runtime identifier to use. - Project '{Project}' targets framework '{targetFramework}'. The dotnet-getdocument tool does not support this framework. + Project '{0}' targets framework '{1}'. The dotnet-getdocument tool does not support this framework. - Using project '{project}'. + Using project '{0}'. Show verbose output. - Writing '{file}'... + Writing '{0}'... Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. @@ -181,6 +181,6 @@ The file to write the result to. - Unable to retrieve '{properrty}' project metadata. Ensure '{msbuildProperty}' is set. + Unable to retrieve '{0}' project metadata. Ensure '{1}' is set. - \ No newline at end of file + diff --git a/src/dotnet-getdocument/dotnet-getdocument.csproj b/src/dotnet-getdocument/dotnet-getdocument.csproj index 73d57bffd9..48569113b1 100644 --- a/src/dotnet-getdocument/dotnet-getdocument.csproj +++ b/src/dotnet-getdocument/dotnet-getdocument.csproj @@ -41,25 +41,6 @@ - - - TextTemplatingFileGenerator - Resources.Designer.cs - - - - - - - - - - True - True - Resources.Designer.tt - - - diff --git a/tools/Resources.tt b/tools/Resources.tt deleted file mode 100644 index 736a0cc442..0000000000 --- a/tools/Resources.tt +++ /dev/null @@ -1,226 +0,0 @@ -<#@ template hostspecific="true" #> -<#@ assembly name="EnvDTE" #> -<#@ assembly name="System.Core" #> -<#@ assembly name="System.Windows.Forms" #> -<#@ import namespace="System.Collections" #> -<#@ import namespace="System.Collections.Generic" #> -<#@ import namespace="System.ComponentModel.Design" #> -<#@ import namespace="System.IO" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Resources" #> -<#@ import namespace="System.Text.RegularExpressions" #> -<#@ import namespace="EnvDTE" #> -<# - var model = LoadResources(); -#> -// - -using System; -using System.Reflection; -using System.Resources; -using JetBrains.Annotations; -<# - if (!model.NoDiagnostics) - { -#> -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.Extensions.Logging; -<# - } -#> - -namespace <#= model.Namespace #> -{ - /// - /// This API supports the GetDocument infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - <#= model.AccessModifier #> static class <#= model.Class #> - { - private static readonly ResourceManager _resourceManager - = new ResourceManager("<#= model.ResourceName #>", typeof(<#= model.Class #>).GetTypeInfo().Assembly); -<# - foreach (var resource in model.Resources) - { -#> - - /// -<# - foreach (var line in Lines(resource.Value)) - { -#> - /// <#= Xml(line) #> -<# - } -#> - /// -<# - if (resource.ForLogging) - { - if (resource.Types.Count() > 6) - { -#> - public static readonly FallbackEventDefinition <#= resource.Name #> - = new FallbackEventDefinition( - <#= resource.EventId #>, - LogLevel.<#= resource.Level #>, - "<#= resource.EventId #>", - _resourceManager.GetString("<#= resource.Name #>")); -<# - } - else - { - var genericTypes = resource.Types.Any() ? ("<" + List(resource.Types) + ">") : ""; -#> - public static readonly EventDefinition<#= genericTypes #> <#= resource.Name #> - = new EventDefinition<#= genericTypes #>( - <#= resource.EventId #>, - LogLevel.<#= resource.Level #>, - "<#= resource.EventId #>", - LoggerMessage.Define<#= genericTypes #>( - LogLevel.<#= resource.Level #>, - <#= resource.EventId #>, - _resourceManager.GetString("<#= resource.Name #>"))); -<# - } - } - else - { - if (resource.Parameters.Any()) - { -#> - public static string <#= resource.Name #>(<#= List("[CanBeNull] object ", resource.Parameters) #>) - => string.Format( - GetString("<#= resource.Name #>", <#= List("nameof(", resource.Parameters, ")") #>), - <#= List(resource.Parameters) #>); -<# - } - else - { -#> - public static string <#= resource.Name #> - => GetString("<#= resource.Name #>"); -<# - } - } - } -#> - - private static string GetString(string name, params string[] formatterNames) - { - var value = _resourceManager.GetString(name); - for (var i = 0; i < formatterNames.Length; i++) - { - value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); - } - - return value; - } - } -} -<#+ - ResourceFile LoadResources() - { - var result = new ResourceFile(); - - if (Session.ContainsKey("AccessModifier")) - { - result.AccessModifier = (string)Session["AccessModifier"]; - }; - - var services = (IServiceProvider)Host; - var dte = (DTE)services.GetService(typeof(DTE)); - - if (!Session.TryGetValue("NoDiagnostics", out var noDiagnostics)) - { - noDiagnostics = false; - } - - result.NoDiagnostics = (bool)noDiagnostics; - - var resourceFile = (string)Session["ResourceFile"]; - if (!Path.IsPathRooted(resourceFile)) - { - resourceFile = Host.ResolvePath(resourceFile); - } - - var resourceProjectItem = dte.Solution.FindProjectItem(resourceFile); - var templateProjectItem = dte.Solution.FindProjectItem(Host.TemplateFile); - var project = templateProjectItem.ContainingProject; - var rootNamespace = (string)project.Properties.Item("RootNamespace").Value; - var resourceDir = Path.GetDirectoryName(resourceFile); - var projectDir = (string)project.Properties.Item("FullPath").Value; - var resourceNamespace = rootNamespace + "." + resourceDir.Substring(projectDir.Length) - .Replace(Path.DirectorySeparatorChar, '.'); - - result.Namespace = (string)resourceProjectItem.Properties.Item("CustomToolNamespace")?.Value; - if (string.IsNullOrEmpty(result.Namespace)) - { - result.Namespace = resourceNamespace; - } - - result.Class = Path.GetFileNameWithoutExtension(resourceFile); - - result.ResourceName = resourceNamespace + "." + result.Class; - - using (var reader = new ResXResourceReader(resourceFile)) - { - reader.UseResXDataNodes = true; - - result.Resources = Enumerable.ToList( - from DictionaryEntry r in reader - select new Resource((ResXDataNode)r.Value)); - } - - return result; - } - - IEnumerable Lines(string value) - => value.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - - string Xml(string value) - => value.Replace("<", "<").Replace(">", ">"); - - string List(IEnumerable items) - => List(null, items); - - string List(string prefix, IEnumerable items, string suffix = null) - => string.Join(", ", items.Select(i => prefix + i + suffix)); - - class ResourceFile - { - public string Namespace { get; set; } - public string AccessModifier { get; set; } = "public"; - public string Class { get; set; } - public string ResourceName { get; set; } - public IEnumerable Resources { get; set; } - public bool NoDiagnostics { get; set; } - } - - class Resource - { - public Resource(ResXDataNode node) - { - Name = node.Name; - Value = (string)node.GetValue((ITypeResolutionService)null); - Parameters = Regex.Matches(Value, @"\{(\w+)\}") - .Cast() - .Select(m => m.Groups[1].Value) - .Distinct() - .ToList(); - - var eventInfo = node.Comment.Split(' '); - Level = eventInfo.FirstOrDefault() ?? "BadLevel"; - EventId = eventInfo.Skip(1).FirstOrDefault() ?? "BadEventId"; - Types = eventInfo.Skip(2).ToList(); - } - - public string Name { get; } - public string Value { get; } - public string EventId { get; } - public string Level { get; } - public bool ForLogging => Name.StartsWith("Log"); - public IEnumerable Parameters { get; } - public IEnumerable Types { get; } - } -#> \ No newline at end of file From d0325ef26472be4e988d4b854a097762335e0979 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sun, 9 Sep 2018 18:12:10 -0700 Subject: [PATCH 05/14] Remove `CodeAnnotations` - #8416 - turns out this required little on top of dougbu/remove.custom.tool --- src/GetDocumentInsider/CodeAnnotations.cs | 23 ------------------- .../dotnet-getdocument.csproj | 1 - 2 files changed, 24 deletions(-) delete mode 100644 src/GetDocumentInsider/CodeAnnotations.cs diff --git a/src/GetDocumentInsider/CodeAnnotations.cs b/src/GetDocumentInsider/CodeAnnotations.cs deleted file mode 100644 index 7a179f24d3..0000000000 --- a/src/GetDocumentInsider/CodeAnnotations.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace JetBrains.Annotations -{ - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field)] - internal sealed class NotNullAttribute : Attribute - { - } - - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field)] - internal sealed class CanBeNullAttribute : Attribute - { - } -} diff --git a/src/dotnet-getdocument/dotnet-getdocument.csproj b/src/dotnet-getdocument/dotnet-getdocument.csproj index 48569113b1..a5f550c9e8 100644 --- a/src/dotnet-getdocument/dotnet-getdocument.csproj +++ b/src/dotnet-getdocument/dotnet-getdocument.csproj @@ -24,7 +24,6 @@ - From a76ca293ef010f7a6cfe0578afcdf0d0da7db004 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sat, 8 Sep 2018 17:46:13 -0700 Subject: [PATCH 06/14] Add missing license headers to src files - #8415 - also correct a typo in Microsoft.AspNetCore.Mvc.Testing files' headers --- src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs | 5 ++++- src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs | 5 ++++- src/GetDocumentInsider/LogWrapper.cs | 5 ++++- src/Microsoft.AspNetCore.Mvc.Razor/IModelTypeProvider.cs | 5 ++++- .../Handlers/CookieContainerHandler.cs | 2 +- .../Handlers/RedirectHandler.cs | 2 +- .../WebApplicationFactory.cs | 2 +- .../WebApplicationFactoryClientOptions.cs | 2 +- .../WebApplicationFactoryContentRootAttribute.cs | 2 +- .../DownloadFileCore.cs | 5 ++++- .../GetFileReferenceMetadata.cs | 5 ++++- .../GetProjectReferenceMetadata.cs | 5 ++++- .../GetUriReferenceMetadata.cs | 5 ++++- .../ILogWrapper.cs | 5 ++++- src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs | 5 ++++- 15 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs index 65b3589af2..a109977c20 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs @@ -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.Extensions.ApiDescription.Client.Commands { diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs index 58d562ef2d..ac90640171 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs @@ -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; using System.Diagnostics; using System.IO; using System.Reflection; diff --git a/src/GetDocumentInsider/LogWrapper.cs b/src/GetDocumentInsider/LogWrapper.cs index b4ee5b4f9b..e7c4b7b8c7 100644 --- a/src/GetDocumentInsider/LogWrapper.cs +++ b/src/GetDocumentInsider/LogWrapper.cs @@ -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.Extensions.ApiDescription.Client { diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/IModelTypeProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/IModelTypeProvider.cs index 7485a15694..276bca6cbc 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/IModelTypeProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/IModelTypeProvider.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/CookieContainerHandler.cs b/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/CookieContainerHandler.cs index bde4250b50..dedcf35f86 100644 --- a/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/CookieContainerHandler.cs +++ b/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/CookieContainerHandler.cs @@ -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. using System.Net; diff --git a/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs b/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs index 8af03645ac..9addd609ec 100644 --- a/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs +++ b/src/Microsoft.AspNetCore.Mvc.Testing/Handlers/RedirectHandler.cs @@ -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. using System; diff --git a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs index 85fcdadba2..8356180bd9 100644 --- a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs +++ b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactory.cs @@ -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. using System; diff --git a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryClientOptions.cs b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryClientOptions.cs index c934b2fd56..cfc0244603 100644 --- a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryClientOptions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryClientOptions.cs @@ -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. using System; diff --git a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryContentRootAttribute.cs b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryContentRootAttribute.cs index a2ea31cb45..51832bd7a8 100644 --- a/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryContentRootAttribute.cs +++ b/src/Microsoft.AspNetCore.Mvc.Testing/WebApplicationFactoryContentRootAttribute.cs @@ -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. using System; diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs index 5fd655fb85..7bae9e0227 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs @@ -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; using System.IO; using System.Net.Http; using System.Net.Sockets; diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs index 2c0717b695..68751b7aa5 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs @@ -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; using System.Collections.Generic; using System.IO; using Microsoft.Build.Framework; diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs index 379e674787..3fd84cf2e0 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs @@ -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; using System.Collections.Generic; using System.IO; using Microsoft.Build.Framework; diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs index fc0f836ca0..d63e2eb684 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs @@ -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; using System.Collections.Generic; using System.IO; using Microsoft.Build.Framework; diff --git a/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs b/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs index 8f7f66396d..261e6df868 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs @@ -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.Extensions.ApiDescription.Client { diff --git a/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs b/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs index 98358ee91b..f058620621 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs @@ -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; using Microsoft.Build.Utilities; namespace Microsoft.Extensions.ApiDescription.Client From 3f001750ad147dc3c69776cf5a6ff7aaad1dadd5 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sun, 9 Sep 2018 18:37:36 -0700 Subject: [PATCH 07/14] Rationalize code sharing between the three code generation projects - #8417 - just two files needed to be moved… --- .../DownloadFileCore.cs | 0 src/GetDocumentInsider/GetDocumentInsider.csproj | 2 -- .../ILogWrapper.cs | 0 .../Microsoft.Extensions.ApiDescription.Client.csproj | 2 ++ 4 files changed, 2 insertions(+), 2 deletions(-) rename src/{Microsoft.Extensions.ApiDescription.Client => GetDocumentInsider}/DownloadFileCore.cs (100%) rename src/{Microsoft.Extensions.ApiDescription.Client => GetDocumentInsider}/ILogWrapper.cs (100%) diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs b/src/GetDocumentInsider/DownloadFileCore.cs similarity index 100% rename from src/Microsoft.Extensions.ApiDescription.Client/DownloadFileCore.cs rename to src/GetDocumentInsider/DownloadFileCore.cs diff --git a/src/GetDocumentInsider/GetDocumentInsider.csproj b/src/GetDocumentInsider/GetDocumentInsider.csproj index 48de9b92d4..3189f54d75 100644 --- a/src/GetDocumentInsider/GetDocumentInsider.csproj +++ b/src/GetDocumentInsider/GetDocumentInsider.csproj @@ -13,8 +13,6 @@ - - diff --git a/src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs b/src/GetDocumentInsider/ILogWrapper.cs similarity index 100% rename from src/Microsoft.Extensions.ApiDescription.Client/ILogWrapper.cs rename to src/GetDocumentInsider/ILogWrapper.cs diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj index 3041a7ea51..94e5128a4d 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj +++ b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj @@ -15,6 +15,8 @@ + + From 87e304334db5bfa8dcedc593c4ebf328fb23c735 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 6 Sep 2018 15:48:55 -0700 Subject: [PATCH 08/14] Remove batching requirements placed on code and document generator providers - #8419 - perform batching and `@(ServiceFileReference)` and `@(Compile)` additions in common code - take advantage of new simplicity in `DefaultDocumentGenerator` target - add metadata serialization / deserialization in support of passing items into `` - also ensure metadata values are escaped before calling `ITaskItem.SetMetadata(...)` - correct typos in Microsoft.Extensions.ApiDescription.Client.* e.g. in comments and metadata names - move last remaining `GenerationTasks` file nits: - combine `_ServiceProjectReferenceGenerator_Restore` and `_ServiceProjectReferenceGenerator_Build` targets - only build web sites projects once - remove unused `buildMultiTargeting` targets - remove qualification of metadata listed in an ``; will always exist - add / remove a few `Condition`s that were missing / redundant - move properties users won't normally set to Microsoft.Extensions.ApiDescription.Client.targets - shorten lines in MSBuild files --- .../GetCurrentItems.cs | 34 +++ .../GetFileReferenceMetadata.cs | 9 +- .../GetProjectReferenceMetadata.cs | 2 + .../GetUriReferenceMetadata.cs | 2 +- .../MetadataSerializer.cs | 147 ++++++++++++ ...oft.Extensions.ApiDescription.Client.props | 99 ++++---- ...t.Extensions.ApiDescription.Client.targets | 220 +++++++++++------- .../GenerationTasks.targets | 29 --- ...t.Extensions.ApiDescription.Client.targets | 9 + 9 files changed, 377 insertions(+), 174 deletions(-) create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/GetCurrentItems.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/MetadataSerializer.cs delete mode 100644 src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetCurrentItems.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetCurrentItems.cs new file mode 100644 index 0000000000..975e716d64 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetCurrentItems.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.Extensions.ApiDescription.Client +{ + /// + /// Restore s from given property value. + /// + public class GetCurrentItems : Task + { + /// + /// The property value to deserialize. + /// + [Required] + public string Input { get; set; } + + /// + /// The restored s. Will never contain more than one item. + /// + [Output] + public ITaskItem[] Outputs { get; set; } + + /// + public override bool Execute() + { + Outputs = new[] { MetadataSerializer.DeserializeMetadata(Input) }; + + return true; + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs index 68751b7aa5..f41d061974 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs @@ -61,18 +61,21 @@ namespace Microsoft.Extensions.ApiDescription.Client if (string.IsNullOrEmpty(@namespace)) { @namespace = isTypeScript ? CSharpNamespace : TypeScriptNamespace; - newItem.SetMetadata("Namespace", @namespace); + MetadataSerializer.SetMetadata(newItem, "Namespace", @namespace); } var outputPath = item.GetMetadata("OutputPath"); if (string.IsNullOrEmpty(outputPath)) { var className = item.GetMetadata("ClassName"); - outputPath = className + (isTypeScript ? ".ts" : ".cs"); + outputPath = $"{className}{(isTypeScript ? ".ts" : ".cs")}"; } outputPath = GetFullPath(outputPath); - newItem.SetMetadata("OutputPath", outputPath); + MetadataSerializer.SetMetadata(newItem, "OutputPath", outputPath); + + // Add metadata which may be used as a property and passed to an inner build. + newItem.SetMetadata("SerializedMetadata", MetadataSerializer.SerializeMetadata(newItem)); } Outputs = outputs.ToArray(); diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs index 3fd84cf2e0..635863d417 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs @@ -52,6 +52,8 @@ namespace Microsoft.Extensions.ApiDescription.Client outputPath = className + (isTypeScript ? ".ts" : ".cs"); } + // Add metadata which may be used as a property and passed to an inner build. + newItem.SetMetadata("SerializedMetadata", MetadataSerializer.SerializeMetadata(newItem)); outputPath = GetFullPath(outputPath); newItem.SetMetadata("OutputPath", outputPath); } diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs index d63e2eb684..873ef57066 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs @@ -95,7 +95,7 @@ namespace Microsoft.Extensions.ApiDescription.Client } documentPath = GetFullPath(documentPath); - newItem.SetMetadata("DocumentPath", documentPath); + MetadataSerializer.SetMetadata(newItem, "DocumentPath", documentPath); } Outputs = outputs.ToArray(); diff --git a/src/Microsoft.Extensions.ApiDescription.Client/MetadataSerializer.cs b/src/Microsoft.Extensions.ApiDescription.Client/MetadataSerializer.cs new file mode 100644 index 0000000000..3f430380a0 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/MetadataSerializer.cs @@ -0,0 +1,147 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.Extensions.ApiDescription.Client +{ + /// + /// Utility methods to serialize and deserialize metadata. + /// + /// + /// Based on and uses the same escaping as + /// https://github.com/Microsoft/msbuild/blob/e70a3159d64f9ed6ec3b60253ef863fa883a99b1/src/Shared/EscapingUtilities.cs + /// + public static class MetadataSerializer + { + private static readonly char[] CharsToEscape = { '%', '*', '?', '@', '$', '(', ')', ';', '\'' }; + private static readonly HashSet CharsToEscapeHash = new HashSet(CharsToEscape); + + /// + /// Add the given and to the . Or, + /// modify existing value to be . + /// + /// The to update. + /// The name of the new metadata. + /// The value of the new metadata. Assumed to be unescaped. + /// Uses same hex-encoded format as MSBuild's EscapeUtilities. + 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()); + } + + /// + /// Serialize metadata for use as a property value passed into an inner build. + /// + /// The item to serialize. + /// A containing the serialized metadata. + /// Uses same hex-encoded format as MSBuild's EscapeUtilities. + 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(); + } + + /// + /// Recreate an with metadata encoded in given . + /// + /// The serialized metadata. + /// The deserialized . + 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))); + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props index 45384b7d3e..2db402f022 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props @@ -6,49 +6,32 @@ <_ApiDescriptionTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_ApiDescriptionTasksAssemblyTarget)/Microsoft.Extensions.ApiDescription.Client.dll <_ApiDescriptionTasksAssemblyTarget /> + + - true + true $([MSBuild]::EnsureTrailingSlash('$(ServiceProjectReferenceDirectory)')) + Condition="'$(ServiceProjectReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceProjectReferenceDirectory)')) - true + true $([MSBuild]::EnsureTrailingSlash('$(ServiceUriReferenceDirectory)')) + Condition="'$(ServiceUriReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceUriReferenceDirectory)')) - true + true $([MSBuild]::EnsureTrailingSlash('$(ServiceFileReferenceDirectory)')) - $(RootNamespace) - $(RootNamespace) - - - _DefaultDocumentGenerator_GetMetadata; - _DefaultDocumentGenerator_Core; - _DefaultDocumentGenerator_SetMetadata - - - _ServiceProjectReferenceGenerator_GetTargetFramework; - _ServiceProjectReferenceGenerator_GetProjectTargetPath; - _ServiceProjectReferenceGenerator_Restore; - _ServiceProjectReferenceGenerator_Build; - _ServiceProjectReferenceGenerator_Core - - - _ServiceUriReferenceGenerator_GetMetadata; - _ServiceUriReferenceGenerator_Core - - - _CheckServiceReferences; - ServiceProjectReferenceGenerator; - ServiceUriReferenceGenerator; - _ServiceFileReferenceGenerator_GetMetadata; - _ServiceFileReferenceGenerator_Core - + Condition="'$(ServiceFileReferenceDirectory)' != ''">$([MSBuild]::EnsureTrailingSlash('$(ServiceFileReferenceDirectory)')) + $(RootNamespace) + $(RootNamespace) Default + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - %(Filename)Client + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets index 6a68aba48b..bd25080826 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets @@ -1,11 +1,34 @@  + + + + _ServiceProjectReferenceGenerator_GetTargetFramework; + _ServiceProjectReferenceGenerator_GetProjectTargetPath; + _ServiceProjectReferenceGenerator_Build; + _ServiceProjectReferenceGenerator_Core; + _ServiceProjectReferenceGenerator_SetMetadata + + + _ServiceUriReferenceGenerator_GetMetadata; + _ServiceUriReferenceGenerator_Core + + + _CheckServiceReferences; + ServiceProjectReferenceGenerator; + ServiceUriReferenceGenerator; + _ServiceFileReferenceGenerator_GetMetadata; + _ServiceFileReferenceGenerator_Core; + _ServiceFileReferenceGenerator_SetMetadata + + + - - - @@ -38,7 +61,7 @@ - $(_TargetFramework) + $(_TargetFramework) <_Temporary Remove="@(_Temporary)" /> @@ -53,17 +76,19 @@ + Inputs="%(ServiceProjectReference.TargetFramework)%(FullPath)')" + Outputs="<not-a-file !>"> <_FullPath>%(ServiceProjectReference.FullPath) - <_TargetFramework>%(ServiceProjectReference.TargetFramework) + <_TargetFramework>%(ServiceProjectReference.ProjectTargetFramework) <_Temporary Remove="@(_Temporary)" /> - + + Condition="'%(ServiceProjectReference.FullPath)' == '$(_FullPath)' AND '%(ProjectTargetFramework)' == '$(_TargetFramework)'"> $(_ProjectTargetPath) <_Temporary Remove="@(_Temporary)" /> @@ -91,99 +116,85 @@ - - - - - + + RemoveProperties="TargetFramework;TargetFrameworks;RuntimeIdentifier" + Targets="Restore;Build" /> - + + + + + - + + + + + + + + + + + + + + + + + + + - + + + + - <_Temporary Remove="@(_Temporary)" /> - <_Temporary Include="@(ServiceProjectReference -> WithMetadataValue('DocumentGenerator', 'Default'))" /> + + + dotnet getdocument --no-build --project %(FullPath) --output %(DocumentPath) + $(DefaultDocumentGeneratorDefaultOptions) + + + %(Command) --framework %(ProjectTargetFramework) + %(Command) --configuration $(Configuration) + %(Command) --configuration %(ProjectConfiguration) + %(Command) --method %(Method) + %(Command) --service %(Service) + %(Command) --uri %(Uri) + %(Command) %(DefaultDocumentGeneratorOptions) + - - + + - - - - <_Command>dotnet getdocument --configuration $(Configuration) --no-build - - - <_Temporary Update="@(_Temporary)"> - $(DefaultDocumentGeneratorDefaultOptions) - $(_Command) --project %(FullPath) --output %(DocumentPath) --framework %(TargetFramework) - - <_Temporary Update="@(_Temporary)"> - %(Command) --uri %(_Temporary.Uri) - - <_Temporary Update="@(_Temporary)"> - %(Command) --service %(_Temporary.Service) --method %(_Temporary.Method) - - <_Temporary Update="@(_Temporary)"> - %(Command) %(_Temporary.Options) - - - - - - - - - - - - - - <_Temporary Remove="@(_Temporary)" /> - - - - - - + <_Temporary Remove="@(_Temporary)" /> - + @@ -199,9 +210,10 @@ DestinationPath="%(DocumentPath)" Overwrite="$(ServiceUriReferenceCheckIfNewer)" /> + - + @@ -209,12 +221,15 @@ - + <_Temporary Remove="@(_Temporary)" /> - + @@ -225,9 +240,38 @@ - + + + + + - + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets b/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets deleted file mode 100644 index 5e73fd66e1..0000000000 --- a/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/GenerationTasks.targets +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets b/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets new file mode 100644 index 0000000000..a9c3d53836 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets @@ -0,0 +1,9 @@ + + + + + + From fb9393febfcff09185b7634ac88893ed6ed08d26 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 19 Sep 2018 10:10:19 -0700 Subject: [PATCH 09/14] Correct metadata additions and add errors about metadata - related to #8419 and (more generally) #7947 - add errors for missing required metadata - add errors for duplicate `%(DocumentPath)` and `%(OutputPath)` metadata - remove `[Required]` for task inputs that may be `null` or empty - correct `%(DocumentPath)`s generated in `GetProjectReferenceMetadata` task - use this task --- .../GetFileReferenceMetadata.cs | 49 ++++++- .../GetProjectReferenceMetadata.cs | 48 +++++-- .../GetUriReferenceMetadata.cs | 11 +- .../Properties/Resources.Designer.cs | 86 +++++++++++ .../Resources.resx | 134 ++++++++++++++++++ ...t.Extensions.ApiDescription.Client.targets | 33 +++-- 6 files changed, 331 insertions(+), 30 deletions(-) create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/Properties/Resources.Designer.cs create mode 100644 src/Microsoft.Extensions.ApiDescription.Client/Resources.resx diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs index f41d061974..1241619418 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs @@ -10,7 +10,8 @@ using Microsoft.Build.Utilities; namespace Microsoft.Extensions.ApiDescription.Client { /// - /// Adds or corrects Namespace and OutputPath metadata in ServiceFileReference items. + /// Adds or corrects ClassName, Namespace and OutputPath metadata in ServiceFileReference items. Also stores final + /// metadata as SerializedMetadata. /// public class GetFileReferenceMetadata : Task { @@ -23,7 +24,6 @@ namespace Microsoft.Extensions.ApiDescription.Client /// /// Default directory for OutputPath values. /// - [Required] public string OutputDirectory { get; set; } /// @@ -49,14 +49,47 @@ namespace Microsoft.Extensions.ApiDescription.Client public override bool Execute() { var outputs = new List(Inputs.Length); + var destinations = new HashSet(); foreach (var item in Inputs) { var newItem = new TaskItem(item); outputs.Add(newItem); var codeGenerator = item.GetMetadata("CodeGenerator"); - var isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase); + 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 isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase); var @namespace = item.GetMetadata("Namespace"); if (string.IsNullOrEmpty(@namespace)) { @@ -67,20 +100,26 @@ namespace Microsoft.Extensions.ApiDescription.Client var outputPath = item.GetMetadata("OutputPath"); if (string.IsNullOrEmpty(outputPath)) { - var className = item.GetMetadata("ClassName"); outputPath = $"{className}{(isTypeScript ? ".ts" : ".cs")}"; } outputPath = GetFullPath(outputPath); MetadataSerializer.SetMetadata(newItem, "OutputPath", 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)); + } + // 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 true; + return !Log.HasLoggedErrors; } private string GetFullPath(string path) diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs index 635863d417..0c682107e5 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs @@ -1,7 +1,6 @@ // 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; @@ -10,14 +9,14 @@ using Microsoft.Build.Utilities; namespace Microsoft.Extensions.ApiDescription.Client { /// - /// Adds or corrects DocumentPath and project-related metadata in ServiceProjectReference items. + /// Adds or corrects DocumentPath and project-related metadata in ServiceProjectReference items. Also stores final + /// metadata as SerializedMetadata. /// public class GetProjectReferenceMetadata : Task { /// /// Default directory for DocumentPath values. /// - [Required] public string DocumentDirectory { get; set; } /// @@ -37,30 +36,53 @@ namespace Microsoft.Extensions.ApiDescription.Client public override bool Execute() { var outputs = new List(Inputs.Length); + var destinations = new HashSet(); + foreach (var item in Inputs) { var newItem = new TaskItem(item); outputs.Add(newItem); - var codeGenerator = item.GetMetadata("CodeGenerator"); - var isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase); - - var outputPath = item.GetMetadata("OutputPath"); - if (string.IsNullOrEmpty(outputPath)) + var documentGenerator = item.GetMetadata("DocumentGenerator"); + if (string.IsNullOrEmpty(documentGenerator)) { - var className = item.GetMetadata("ClassName"); - outputPath = className + (isTypeScript ? ".ts" : ".cs"); + // 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)); - outputPath = GetFullPath(outputPath); - newItem.SetMetadata("OutputPath", outputPath); } Outputs = outputs.ToArray(); - return true; + return !Log.HasLoggedErrors; } private string GetFullPath(string path) diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs index 873ef57066..6870d2a337 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs @@ -17,7 +17,6 @@ namespace Microsoft.Extensions.ApiDescription.Client /// /// Default directory for DocumentPath metadata values. /// - [Required] public string DocumentDirectory { get; set; } /// @@ -36,6 +35,7 @@ namespace Microsoft.Extensions.ApiDescription.Client public override bool Execute() { var outputs = new List(Inputs.Length); + var destinations = new HashSet(); foreach (var item in Inputs) { var newItem = new TaskItem(item); @@ -96,11 +96,18 @@ namespace Microsoft.Extensions.ApiDescription.Client 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 true; + return !Log.HasLoggedErrors; } private string GetFullPath(string path) diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Properties/Resources.Designer.cs b/src/Microsoft.Extensions.ApiDescription.Client/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..27049a4842 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/Properties/Resources.Designer.cs @@ -0,0 +1,86 @@ +// +namespace Microsoft.Extensions.ApiDescription.Client +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// Multiple items have OutputPath='{0}'. All ServiceFileReference, ServiceProjectReference and ServiceUriReference items must have unique OutputPath metadata. + /// + internal static string DuplicateFileOutputPaths + { + get => GetString("DuplicateFileOutputPaths"); + } + + /// + /// Multiple items have OutputPath='{0}'. All ServiceFileReference, ServiceProjectReference and ServiceUriReference items must have unique OutputPath metadata. + /// + internal static string FormatDuplicateFileOutputPaths(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("DuplicateFileOutputPaths"), p0); + + /// + /// Mutliple ServiceProjectReference items have DocumentPath='{0}'. ServiceProjectReference items must have unique DocumentPath metadata. + /// + internal static string DuplicateProjectDocumentPaths + { + get => GetString("DuplicateProjectDocumentPaths"); + } + + /// + /// Mutliple ServiceProjectReference items have DocumentPath='{0}'. ServiceProjectReference items must have unique DocumentPath metadata. + /// + internal static string FormatDuplicateProjectDocumentPaths(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("DuplicateProjectDocumentPaths"), p0); + + /// + /// Mutliple ServiceUriReference items have DocumentPath='{0}'. ServiceUriReference items must have unique DocumentPath metadata. + /// + internal static string DuplicateUriDocumentPaths + { + get => GetString("DuplicateUriDocumentPaths"); + } + + /// + /// Mutliple ServiceUriReference items have DocumentPath='{0}'. ServiceUriReference items must have unique DocumentPath metadata. + /// + internal static string FormatDuplicateUriDocumentPaths(object p0) + => string.Format(CultureInfo.CurrentCulture, GetString("DuplicateUriDocumentPaths"), p0); + + /// + /// Invalid {0} metadata value for {1} item '{2}'. {0} metadata must not be set to the empty string. + /// + internal static string InvalidEmptyMetadataValue + { + get => GetString("InvalidEmptyMetadataValue"); + } + + /// + /// Invalid {0} metadata value for {1} item '{2}'. {0} metadata must not be set to the empty string. + /// + 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; + } + } +} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Resources.resx b/src/Microsoft.Extensions.ApiDescription.Client/Resources.resx new file mode 100644 index 0000000000..68fa954f09 --- /dev/null +++ b/src/Microsoft.Extensions.ApiDescription.Client/Resources.resx @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Multiple items have OutputPath='{0}'. All ServiceFileReference, ServiceProjectReference and ServiceUriReference items must have unique OutputPath metadata. + ServiceProjectReference and ServiceUriReference items become ServiceFileReference items and all ServiceFileReference items must have unique OutputPath metadata. + + + Mutliple ServiceProjectReference items have DocumentPath='{0}'. ServiceProjectReference items must have unique DocumentPath metadata. + + + Mutliple ServiceUriReference items have DocumentPath='{0}'. ServiceUriReference items must have unique DocumentPath metadata. + Ignore corner case of ServiceProjectReference and ServiceUriReference items having the same DocumentPath. + + + Invalid {0} metadata value for {1} item '{2}'. {0} metadata must not be set to the empty string. + + \ No newline at end of file diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets index bd25080826..ecbac4412e 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets @@ -5,6 +5,7 @@ _ServiceProjectReferenceGenerator_GetTargetFramework; _ServiceProjectReferenceGenerator_GetProjectTargetPath; + _ServiceProjectReferenceGenerator_GetMetadata; _ServiceProjectReferenceGenerator_Build; _ServiceProjectReferenceGenerator_Core; _ServiceProjectReferenceGenerator_SetMetadata @@ -14,7 +15,6 @@ _ServiceUriReferenceGenerator_Core - _CheckServiceReferences; ServiceProjectReferenceGenerator; ServiceUriReferenceGenerator; _ServiceFileReferenceGenerator_GetMetadata; @@ -23,15 +23,6 @@ - - - - - - @@ -116,6 +107,28 @@ + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + + + + + + + <_Temporary Remove="@(_Temporary)" /> + + + + + + Date: Tue, 25 Sep 2018 15:23:50 -0700 Subject: [PATCH 10/14] Fix a few issues with Microsoft.Extensions.ApiDescription.Client targets - follow-ups to 1646345955 and 9d109f5956 - fix `%(Command)` updates in `DefaultDocumentGenerator` target - later references to metadata values set within an item are not up-to-date - qualify values for `%(SourceProject)`, `%(SourceUri)` and `%(SourceDocument)` when setting that metadata - MSBuild can't distinguish unqualified metadata references unless using `` - fix `@(CurrentServiceFileReference)` items - was a copy 'n paste error in `_ServiceFileReferenceGenerator_Core` target - remove per-language default namespace values - do not add TypeScript files to `@(Compile)`; generally enhance final item additions - use `$(DefaultLanguageSourceExtension)` to help here - exclude generated source files with `%(OutputPath)` that does not match `$(DefaultLanguageSourceExtension)` - really support `%(OutputPath)` directories - stick with current `$(TargetFramework)` when building `...ReferenceGenerator_Inner` targets - `%(ProjectTargetFramework)` will not exist for all `@(ServiceFileReference)` items - building the current project, not a service project; `%(ProjectTargetFramework)` may not be supported nits: - shorten a few more long lines in Microsoft.Extensions.ApiDescription.Client.targets - reduce logging from that file - do not include `%(SerializedMetadata)` in `%(SerializedMetadata)` - caused extra-long serialization of items that were originally `@(ServiceProjectReference)`s - add more info to various comments - always use element syntax for metadata additions --- .../GetFileReferenceMetadata.cs | 54 +++---- ...oft.Extensions.ApiDescription.Client.props | 27 ++-- ...t.Extensions.ApiDescription.Client.targets | 133 ++++++++++++------ 3 files changed, 128 insertions(+), 86 deletions(-) diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs index 1241619418..54ae8b7500 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs @@ -15,23 +15,25 @@ namespace Microsoft.Extensions.ApiDescription.Client /// public class GetFileReferenceMetadata : Task { + private const string TypeScriptLanguageName = "TypeScript"; + /// - /// Default Namespace metadata value for C# output. + /// Extension to use in default OutputPath metadata value. Ignored when generating TypeScript. /// [Required] - public string CSharpNamespace { get; set; } + public string Extension { get; set; } + + /// + /// Default Namespace metadata value. + /// + [Required] + public string Namespace { get; set; } /// /// Default directory for OutputPath values. /// public string OutputDirectory { get; set; } - /// - /// Default Namespace metadata value for TypeScript output. - /// - [Required] - public string TypeScriptNamespace { get; set; } - /// /// The ServiceFileReference items to update. /// @@ -39,8 +41,7 @@ namespace Microsoft.Extensions.ApiDescription.Client public ITaskItem[] Inputs { get; set; } /// - /// The updated ServiceFileReference items. Will include Namespace and OutputPath metadata. OutputPath metadata - /// will contain full paths. + /// The updated ServiceFileReference items. Will include ClassName, Namespace and OutputPath metadata. /// [Output] public ITaskItem[] Outputs{ get; set; } @@ -50,6 +51,7 @@ namespace Microsoft.Extensions.ApiDescription.Client { var outputs = new List(Inputs.Length); var destinations = new HashSet(); + foreach (var item in Inputs) { var newItem = new TaskItem(item); @@ -89,22 +91,24 @@ namespace Microsoft.Extensions.ApiDescription.Client MetadataSerializer.SetMetadata(newItem, "ClassName", className); } - var isTypeScript = codeGenerator.EndsWith("TypeScript", StringComparison.OrdinalIgnoreCase); var @namespace = item.GetMetadata("Namespace"); if (string.IsNullOrEmpty(@namespace)) { - @namespace = isTypeScript ? CSharpNamespace : TypeScriptNamespace; - MetadataSerializer.SetMetadata(newItem, "Namespace", @namespace); + MetadataSerializer.SetMetadata(newItem, "Namespace", Namespace); } var outputPath = item.GetMetadata("OutputPath"); if (string.IsNullOrEmpty(outputPath)) { - outputPath = $"{className}{(isTypeScript ? ".ts" : ".cs")}"; + var isTypeScript = codeGenerator.EndsWith(TypeScriptLanguageName, StringComparison.OrdinalIgnoreCase); + outputPath = $"{className}{(isTypeScript ? ".ts" : Extension)}"; } - outputPath = GetFullPath(outputPath); - MetadataSerializer.SetMetadata(newItem, "OutputPath", outputPath); + // 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)) { @@ -113,7 +117,10 @@ namespace Microsoft.Extensions.ApiDescription.Client 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)); } @@ -121,20 +128,5 @@ namespace Microsoft.Extensions.ApiDescription.Client return !Log.HasLoggedErrors; } - - private string GetFullPath(string path) - { - if (!Path.IsPathRooted(path)) - { - if (!string.IsNullOrEmpty(OutputDirectory)) - { - path = Path.Combine(OutputDirectory, path); - } - - path = Path.GetFullPath(path); - } - - return path; - } } } diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props index 2db402f022..d01b8044e8 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props @@ -12,7 +12,10 @@ - + true @@ -28,10 +31,8 @@ Condition="'$(ServiceFileReferenceCheckIfNewer)' == ''">true $([MSBuild]::EnsureTrailingSlash('$(ServiceFileReferenceDirectory)')) - $(RootNamespace) - $(RootNamespace) + + - + Default @@ -107,17 +111,20 @@ - + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets index ecbac4412e..e7c60f9017 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets @@ -1,6 +1,6 @@  - + _ServiceProjectReferenceGenerator_GetTargetFramework; @@ -25,8 +25,10 @@ - - + @@ -45,14 +47,17 @@ - + <_TargetFrameworks>%(_Temporary.TargetFrameworks) <_TargetFramework>$(_TargetFrameworks.Split(';')[0]) - $(_TargetFramework) + $(_TargetFramework) <_Temporary Remove="@(_Temporary)" /> @@ -64,8 +69,11 @@ - - + @@ -77,9 +85,6 @@ <_Temporary Remove="@(_Temporary)" /> - + Condition="'%(FullPath)' == '$(_FullPath)' AND '%(ProjectTargetFramework)' == '$(_TargetFramework)'"> $(_ProjectTargetPath) <_Temporary Remove="@(_Temporary)" /> @@ -113,7 +118,8 @@ <_Temporary Remove="@(_Temporary)" /> - + @@ -124,9 +130,6 @@ <_Temporary Remove="@(_Temporary)" /> - - - - + - - - @@ -164,8 +165,9 @@ + Condition="Exists('%(ServiceProjectReference.DocumentPath)')"> + %(ServiceProjectReference.FullPath) + @@ -174,30 +176,36 @@ - - - dotnet getdocument --no-build --project %(FullPath) --output %(DocumentPath) $(DefaultDocumentGeneratorDefaultOptions) + $(Configuration) - + %(Command) --framework %(ProjectTargetFramework) - %(Command) --configuration $(Configuration) - %(Command) --configuration %(ProjectConfiguration) + + %(Command) --method %(Method) + + %(Command) --service %(Service) + + %(Command) --uri %(Uri) - %(Command) %(DefaultDocumentGeneratorOptions) + + + %(Command) --configuration %(ProjectConfiguration) %(DefaultDocumentGeneratorOptions) - - + + + @@ -226,7 +234,9 @@ - + + %(ServiceUriReference.Identity) + @@ -240,9 +250,9 @@ + Extension="$(DefaultLanguageSourceExtension)" + Namespace="$(RootNamespace)" + OutputDirectory="$(ServiceFileReferenceDirectory)"> @@ -259,16 +269,14 @@ - + - - - @@ -279,8 +287,43 @@ unique. --> - - + <_Files Remove="@(_Files)" /> + <_Files Include="@(ServiceFileReference -> '%(OutputPath)')" + Condition="$([System.IO.File]::Exists('%(ServiceFileReference.OutputPath)'))"> + $([System.IO.Path]::GetExtension('%(ServiceFileReference.OutputPath)')) + + <_Directories Remove="@(_Directories)" /> + <_Directories Include="@(ServiceFileReference -> '%(OutputPath)')" + Condition="Exists('%(ServiceFileReference.OutputPath)') AND ! $([System.IO.File]::Exists('%(ServiceFileReference.OutputPath)'))" /> + + + + + %(_Files.FullPath) + + + + + %(ServiceFileReference.FullPath) + + + + + + %(_Directories.FullPath) + + + + + %(_Directories.FullPath) + + + <_Files Remove="@(_Files)" /> + <_Directories Remove="@(_Directories)" /> From 5a58f81d8d9858d735aad21991413671cbf7dca4 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 3 Oct 2018 20:08:14 -0700 Subject: [PATCH 11/14] Use Internal.AspNetCore.Sdk as an MSBuild SDK in new projects - follow-up to 5bddd226a3 --- src/GetDocumentInsider/GetDocumentInsider.csproj | 2 +- .../Microsoft.Extensions.ApiDescription.Client.csproj | 2 +- src/dotnet-getdocument/dotnet-getdocument.csproj | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/GetDocumentInsider/GetDocumentInsider.csproj b/src/GetDocumentInsider/GetDocumentInsider.csproj index 3189f54d75..93849f9cc4 100644 --- a/src/GetDocumentInsider/GetDocumentInsider.csproj +++ b/src/GetDocumentInsider/GetDocumentInsider.csproj @@ -1,4 +1,4 @@ - + GetDocument.Insider GetDocument Command-line Tool inside man diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj index 94e5128a4d..daec0b3b26 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj +++ b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj @@ -1,4 +1,4 @@ - + $(GenerateNuspecDependsOn);PopulateNuspec diff --git a/src/dotnet-getdocument/dotnet-getdocument.csproj b/src/dotnet-getdocument/dotnet-getdocument.csproj index a5f550c9e8..53967535a7 100644 --- a/src/dotnet-getdocument/dotnet-getdocument.csproj +++ b/src/dotnet-getdocument/dotnet-getdocument.csproj @@ -1,7 +1,4 @@ - - - - + $(GenerateNuspecDependsOn);PopulateNuspec From d3442f35904e8ae5c60fe03c6818f206bc32a6db Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Tue, 11 Sep 2018 16:20:07 -0700 Subject: [PATCH 12/14] Create a single Microsoft.Extensions.ApiDescription.Client package - #8428 - add signing-related and PackageVerifier configuration for new package - remove packaging configuration from dotnet-getdocument project - adjust `dotnet-getdocument` invocation to its new location - remove use of nonexistent (ignored) `dotnet-getdocument --no-build` option Remove `--uri` feature from `dotnet-getdocument` - reduce dependencies from Microsoft.AspNetCore.TestHost to Microsoft.AspNetCore.Hosting.Abstractions - assume web site depends on that - merge `DownloadFileCore` into `DownloadFile` - remove other unecessary code e.g. `WrappedException` was never `throw`n Correct issues in `DownloadFile` - e.g. dispose of `responseStream`, use `await` more, support FIPS-compliant machines nits: - clean up `Project` and the metadata it fetches - remove unnecessary `.props` and `.targets` files --- NuGetPackageVerifier.json | 19 ++- build/dependencies.props | 4 +- .../Commands/GetDocumentCommand.cs | 11 +- .../Commands/GetDocumentCommandContext.cs | 2 - .../Commands/GetDocumentCommandWorker.cs | 112 ++------------- src/GetDocumentInsider/DownloadFileCore.cs | 121 ---------------- .../GetDocumentInsider.csproj | 6 +- src/GetDocumentInsider/ILogWrapper.cs | 53 ------- src/GetDocumentInsider/Json.cs | 18 --- src/GetDocumentInsider/LogWrapper.cs | 31 ---- src/GetDocumentInsider/Program.cs | 5 +- .../Properties/Resources.Designer.cs | 126 ---------------- src/GetDocumentInsider/Resources.resx | 29 +--- src/GetDocumentInsider/WrappedException.cs | 24 ---- .../DownloadFile.cs | 134 ++++++++++++++++-- .../LogWrapper.cs | 38 ----- ...ft.Extensions.ApiDescription.Client.csproj | 47 ++++-- ...ft.Extensions.ApiDescription.Client.nuspec | 16 ++- .../ServiceProjectReferenceMetadata.targets | 32 ----- ...oft.Extensions.ApiDescription.Client.props | 5 - ...t.Extensions.ApiDescription.Client.targets | 5 +- .../Commands/InvokeCommand.cs | 6 - src/dotnet-getdocument/Project.cs | 81 +++++------ .../Properties/Resources.Designer.cs | 4 +- src/dotnet-getdocument/Resources.resx | 2 +- .../ServiceProjectReferenceMetadata.props | 17 --- .../ServiceProjectReferenceMetadata.targets | 26 ++-- .../dotnet-getdocument.csproj | 68 +-------- .../dotnet-getdocument.nuspec | 28 ---- 29 files changed, 261 insertions(+), 809 deletions(-) delete mode 100644 src/GetDocumentInsider/DownloadFileCore.cs delete mode 100644 src/GetDocumentInsider/ILogWrapper.cs delete mode 100644 src/GetDocumentInsider/Json.cs delete mode 100644 src/GetDocumentInsider/LogWrapper.cs delete mode 100644 src/GetDocumentInsider/WrappedException.cs delete mode 100644 src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs delete mode 100644 src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets delete mode 100644 src/dotnet-getdocument/ServiceProjectReferenceMetadata.props delete mode 100644 src/dotnet-getdocument/dotnet-getdocument.nuspec diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index b153ab1515..079b7cef51 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,7 +1,16 @@ { - "Default": { - "rules": [ - "DefaultCompositeRule" - ] + "Default": { + "rules": [ + "DefaultCompositeRule" + ], + "packages": { + "Microsoft.Extensions.ApiDescription.Client": { + "Exclusions": { + "BUILD_ITEMS_FRAMEWORK": { + "*": "Package includes tool with different target frameworks." + } + } + } } -} \ No newline at end of file + } +} diff --git a/build/dependencies.props b/build/dependencies.props index 304c16413f..eed739b78e 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -7,7 +7,7 @@ is not otherwise referenced. They avoid unnecessary changes to the Universe build graph or to product dependencies. Do not use these properties elsewhere. --> - + 0.9.9 0.10.13 2.1.1 @@ -32,6 +32,7 @@ 2.2.0-preview3-35359 2.2.0-preview3-35359 2.2.0-preview3-35359 + 2.0.0 2.2.0-preview3-35359 2.2.0-preview3-35359 2.2.0-preview3-35359 @@ -54,7 +55,6 @@ 2.2.0-preview3-35359 2.2.0-preview3-35359 2.2.0-preview3-35359 - 2.0.0 2.2.0-preview3-35359 2.2.0-preview3-35359 5.2.6 diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs index 583031b324..cd45255f09 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs @@ -17,13 +17,11 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands internal const string FallbackDocumentName = "v1"; internal const string FallbackMethod = "Generate"; internal const string FallbackService = "Microsoft.Extensions.ApiDescription.IDocumentProvider"; - private const string WorkerType = "Microsoft.Extensions.ApiDescription.Client.Commands.GetDocumentCommandWorker"; private CommandOption _documentName; private CommandOption _method; private CommandOption _output; private CommandOption _service; - private CommandOption _uri; public override void Configure(CommandLineApplication command) { @@ -35,7 +33,6 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands _method = command.Option("--method ", Resources.FormatMethodDescription(FallbackMethod)); _output = command.Option("--output ", Resources.OutputDescription); _service = command.Option("--service ", Resources.FormatServiceDescription(FallbackService)); - _uri = command.Option("--uri ", Resources.UriDescription); } protected override void Validate() @@ -131,12 +128,9 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands #error target frameworks need to be updated. #endif - // Now safe to reference TestHost type. + // Now safe to reference the application's code. try { - var workerType = thisAssembly.GetType(WorkerType, throwOnError: true); - var methodInfo = workerType.GetMethod("Process", BindingFlags.Public | BindingFlags.Static); - var assemblyPath = AssemblyPath.Value(); var context = new GetDocumentCommandContext { @@ -147,10 +141,9 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands Method = _method.Value(), Output = _output.Value(), Service = _service.Value(), - Uri = _uri.Value(), }; - return (int)methodInfo.Invoke(obj: null, parameters: new[] { context }); + return GetDocumentCommandWorker.Process(context); } catch (Exception ex) { diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs index a109977c20..c4fc0b6e45 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs @@ -21,7 +21,5 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands public string Output { get; set; } public string Service { get; set; } - - public string Uri { get; set; } } } diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs index ac90640171..b0434e453c 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs @@ -2,15 +2,10 @@ // 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.Reflection; -using System.Threading; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; namespace Microsoft.Extensions.ApiDescription.Client.Commands { @@ -34,25 +29,10 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands } var success = TryProcess(context, services); - if (!success && string.IsNullOrEmpty(context.Uri)) + if (!success) { - return 4; - } - - var builder = GetBuilder(entryPointType, context.AssemblyPath, context.AssemblyName); - if (builder == null) - { - return 5; - } - - // Mute the HttpsRedirectionMiddleware warning about HTTPS configuration. - builder.ConfigureLogging(loggingBuilder => loggingBuilder.AddFilter( - "Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware", - LogLevel.Error)); - - using (var server = new TestServer(builder)) - { - ProcessAsync(context, server).Wait(); + // As part of the aspnet/Mvc#8425 fix, return 4 here. + return 0; } return 0; @@ -95,15 +75,9 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands 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); - if (string.IsNullOrEmpty(context.Uri) && !File.Exists(context.Output)) - { - Reporter.WriteError(message); - } - else - { - Reporter.WriteWarning(message); - } + Reporter.WriteWarning(message); } return success; @@ -111,35 +85,14 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands catch (Exception ex) { var message = FormatException(ex); - if (string.IsNullOrEmpty(context.Uri) && !File.Exists(context.Output)) - { - Reporter.WriteError(message); - } - else - { - Reporter.WriteWarning(message); - } + + // As part of the aspnet/Mvc#8425 fix, make this an error unless the file already exists. + Reporter.WriteWarning(message); return false; } } - public static async Task ProcessAsync(GetDocumentCommandContext context, TestServer server) - { - - Debug.Assert(!string.IsNullOrEmpty(context.Uri)); - Reporter.WriteInformation(Resources.FormatUsingUri(context.Uri)); - - var httpClient = server.CreateClient(); - await DownloadFileCore.DownloadAsync( - context.Uri, - context.Output, - httpClient, - new LogWrapper(), - CancellationToken.None, - timeoutSeconds: 60); - } - // TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available. private static IServiceProvider GetServices(Type entryPointType, string assemblyPath, string assemblyName) { @@ -203,54 +156,7 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands } } - // Startup - return new WebHostBuilder().UseStartup(assemblyName).Build().Services; - } - - // TODO: Use Microsoft.AspNetCore.Hosting.WebHostBuilderFactory.Sources once we have dev feed available. - private static IWebHostBuilder GetBuilder(Type entryPointType, string assemblyPath, string assemblyName) - { - var methodInfo = entryPointType.GetMethod("BuildWebHost"); - if (methodInfo != null) - { - // BuildWebHost cannot be used. Fall through, most likely to Startup fallback. - Reporter.WriteWarning( - "BuildWebHost method cannot be used. Falling back to minimal Startup configuration."); - } - - methodInfo = entryPointType.GetMethod("CreateWebHostBuilder"); - if (methodInfo != null) - { - // CreateWebHostBuilder - var parameters = methodInfo.GetParameters(); - if (!methodInfo.IsStatic || - parameters.Length != 1 || - typeof(string[]) != parameters[0].ParameterType || - typeof(IWebHostBuilder) != methodInfo.ReturnType) - { - Reporter.WriteError( - "CreateWebHostBuilder method found in {assemblyPath} does not have expected signature."); - - return null; - } - - try - { - var args = new[] { Array.Empty() }; - var builder = (IWebHostBuilder)methodInfo.Invoke(obj: null, parameters: args); - - return builder; - } - catch (Exception ex) - { - Reporter.WriteError($"CreateWebHostBuilder method threw: {FormatException(ex)}"); - - return null; - } - } - - // Startup - return new WebHostBuilder().UseStartup(assemblyName); + return null; } private static string FormatException(Exception exception) diff --git a/src/GetDocumentInsider/DownloadFileCore.cs b/src/GetDocumentInsider/DownloadFileCore.cs deleted file mode 100644 index 7bae9e0227..0000000000 --- a/src/GetDocumentInsider/DownloadFileCore.cs +++ /dev/null @@ -1,121 +0,0 @@ -// 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.Security.Cryptography; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Extensions.ApiDescription.Client -{ - internal static class DownloadFileCore - { - public static async Task DownloadAsync( - string uri, - string destinationPath, - HttpClient httpClient, - ILogWrapper log, - CancellationToken cancellationToken, - int timeoutSeconds) - { - // Timeout if the response has not begun within 1 minute - httpClient.Timeout = TimeSpan.FromMinutes(1); - - var destinationExists = File.Exists(destinationPath); - var reachedCopy = false; - try - { - using (var response = await httpClient.GetAsync(uri, cancellationToken)) - { - response.EnsureSuccessStatusCode(); - cancellationToken.ThrowIfCancellationRequested(); - - using (var responseStreamTask = response.Content.ReadAsStreamAsync()) - { - var finished = await Task.WhenAny( - responseStreamTask, - Task.Delay(TimeSpan.FromSeconds(timeoutSeconds))); - - if (!ReferenceEquals(responseStreamTask, finished)) - { - throw new TimeoutException($"Download failed to complete in {timeoutSeconds} seconds."); - } - - var responseStream = await responseStreamTask; - if (destinationExists) - { - // Check hashes before using the downloaded information. - var downloadHash = GetHash(responseStream); - responseStream.Position = 0L; - - byte[] destinationHash; - using (var destinationStream = File.OpenRead(destinationPath)) - { - destinationHash = GetHash(destinationStream); - } - - var sameHashes = downloadHash.LongLength == destinationHash.LongLength; - for (var i = 0L; sameHashes && i < downloadHash.LongLength; i++) - { - sameHashes = downloadHash[i] == destinationHash[i]; - } - - if (sameHashes) - { - log.LogInformational($"Not overwriting existing and matching file '{destinationPath}'."); - return; - } - } - else - { - // May need to create directory to hold the file. - var destinationDirectory = Path.GetDirectoryName(destinationPath); - if (!(string.IsNullOrEmpty(destinationDirectory) || Directory.Exists(destinationDirectory))) - { - Directory.CreateDirectory(destinationDirectory); - } - } - - // Create or overwrite the destination file. - reachedCopy = true; - using (var outStream = File.Create(destinationPath)) - { - responseStream.CopyTo(outStream); - } - } - } - } - catch (HttpRequestException ex) when (destinationExists) - { - if (ex.InnerException is SocketException socketException) - { - log.LogWarning($"Unable to download {uri}, socket error code '{socketException.SocketErrorCode}'."); - } - else - { - log.LogWarning($"Unable to download {uri}: {ex.Message}"); - } - } - catch (Exception ex) - { - log.LogError($"Downloading '{uri}' failed."); - log.LogError(ex, showStackTrace: true); - if (reachedCopy) - { - File.Delete(destinationPath); - } - } - } - - private static byte[] GetHash(Stream stream) - { - using (var algorithm = SHA256.Create()) - { - return algorithm.ComputeHash(stream); - } - } - } -} diff --git a/src/GetDocumentInsider/GetDocumentInsider.csproj b/src/GetDocumentInsider/GetDocumentInsider.csproj index 93849f9cc4..b2c4fed5c6 100644 --- a/src/GetDocumentInsider/GetDocumentInsider.csproj +++ b/src/GetDocumentInsider/GetDocumentInsider.csproj @@ -13,6 +13,10 @@ - + + + + + diff --git a/src/GetDocumentInsider/ILogWrapper.cs b/src/GetDocumentInsider/ILogWrapper.cs deleted file mode 100644 index 261e6df868..0000000000 --- a/src/GetDocumentInsider/ILogWrapper.cs +++ /dev/null @@ -1,53 +0,0 @@ -// 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.Client -{ - internal interface ILogWrapper - { - /// - /// Logs specified informational . Implementations should be thread safe. - /// - /// The message to log. - /// Optional arguments for formatting the string. - /// - /// Thrown when is . - /// - void LogInformational(string message, params object[] messageArgs); - - /// - /// Logs a warning with the specified . Implementations should be thread safe. - /// - /// The message to log. - /// Optional arguments for formatting the string. - /// - /// Thrown when is . - /// - void LogWarning(string message, params object[] messageArgs); - - /// - /// Logs an error with the specified . Implementations should be thread safe. - /// - /// The message to log. - /// Optional arguments for formatting the string. - /// - /// Thrown when is . - /// - void LogError(string message, params object[] messageArgs); - - /// - /// Logs an error with the message and (optionally) the stack trace of the given . - /// Implementations should be thread safe. - /// - /// The to log. - /// - /// If , append stack trace to 's message. - /// - /// - /// Thrown when is . - /// - void LogError(Exception exception, bool showStackTrace); - } -} diff --git a/src/GetDocumentInsider/Json.cs b/src/GetDocumentInsider/Json.cs deleted file mode 100644 index 53885c5825..0000000000 --- a/src/GetDocumentInsider/Json.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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.Client -{ - internal static class Json - { - public static CommandOption ConfigureOption(CommandLineApplication command) - => command.Option("--json", Resources.JsonDescription); - - public static string Literal(string text) - => text != null - ? "\"" + text.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"" - : "null"; - } -} diff --git a/src/GetDocumentInsider/LogWrapper.cs b/src/GetDocumentInsider/LogWrapper.cs deleted file mode 100644 index e7c4b7b8c7..0000000000 --- a/src/GetDocumentInsider/LogWrapper.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Client -{ - public class LogWrapper : ILogWrapper - { - public void LogError(string message, params object[] messageArgs) - { - Reporter.WriteError(string.Format(message, messageArgs)); - } - - public void LogError(Exception exception, bool showStackTrace) - { - var message = showStackTrace ? exception.ToString() : exception.Message; - Reporter.WriteError(message); - } - - public void LogInformational(string message, params object[] messageArgs) - { - Reporter.WriteInformation(string.Format(message, messageArgs)); - } - - public void LogWarning(string message, params object[] messageArgs) - { - Reporter.WriteWarning(string.Format(message, messageArgs)); - } - } -} diff --git a/src/GetDocumentInsider/Program.cs b/src/GetDocumentInsider/Program.cs index 2f2f43a4c0..af1bdc298a 100644 --- a/src/GetDocumentInsider/Program.cs +++ b/src/GetDocumentInsider/Program.cs @@ -30,10 +30,7 @@ namespace Microsoft.Extensions.ApiDescription.Client } catch (Exception ex) { - if (ex is CommandException - || ex is CommandParsingException - || (ex is WrappedException wrappedException - && wrappedException.Type == "Microsoft.Extensions.ApiDescription.Client.Design.OperationException")) + if (ex is CommandException || ex is CommandParsingException) { Reporter.WriteVerbose(ex.ToString()); } diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.cs b/src/GetDocumentInsider/Properties/Resources.Designer.cs index 460ca76235..c9576ef8c0 100644 --- a/src/GetDocumentInsider/Properties/Resources.Designer.cs +++ b/src/GetDocumentInsider/Properties/Resources.Designer.cs @@ -24,20 +24,6 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static string FormatAssemblyDescription() => GetString("AssemblyDescription"); - /// - /// Show JSON output. - /// - internal static string JsonDescription - { - get => GetString("JsonDescription"); - } - - /// - /// Show JSON output. - /// - internal static string FormatJsonDescription() - => GetString("JsonDescription"); - /// /// Missing required option '--{0}'. /// @@ -94,48 +80,6 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static string FormatPrefixDescription() => GetString("PrefixDescription"); - /// - /// Using application base '{0}'. - /// - internal static string UsingApplicationBase - { - get => GetString("UsingApplicationBase"); - } - - /// - /// Using application base '{0}'. - /// - internal static string FormatUsingApplicationBase(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("UsingApplicationBase"), p0); - - /// - /// Using assembly '{0}'. - /// - internal static string UsingAssembly - { - get => GetString("UsingAssembly"); - } - - /// - /// Using assembly '{0}'. - /// - internal static string FormatUsingAssembly(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("UsingAssembly"), p0); - - /// - /// Using configuration file '{0}'. - /// - internal static string UsingConfigurationFile - { - get => GetString("UsingConfigurationFile"); - } - - /// - /// Using configuration file '{0}'. - /// - internal static string FormatUsingConfigurationFile(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("UsingConfigurationFile"), p0); - /// /// Show verbose output. /// @@ -150,34 +94,6 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static string FormatVerboseDescription() => GetString("VerboseDescription"); - /// - /// Writing '{0}'... - /// - internal static string WritingFile - { - get => GetString("WritingFile"); - } - - /// - /// Writing '{0}'... - /// - internal static string FormatWritingFile(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("WritingFile"), p0); - - /// - /// Using working directory '{0}'. - /// - internal static string UsingWorkingDirectory - { - get => GetString("UsingWorkingDirectory"); - } - - /// - /// Using working directory '{0}'. - /// - internal static string FormatUsingWorkingDirectory(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("UsingWorkingDirectory"), p0); - /// /// Location from which inside man was copied (in the .NET Framework case) or loaded. /// @@ -192,20 +108,6 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static string FormatToolsDirectoryDescription() => GetString("ToolsDirectoryDescription"); - /// - /// The URI to download the document from. - /// - internal static string UriDescription - { - get => GetString("UriDescription"); - } - - /// - /// The URI to download the document from. - /// - internal static string FormatUriDescription() - => GetString("UriDescription"); - /// /// The name of the method to invoke on the '--service' instance. Default value '{0}'. /// @@ -234,20 +136,6 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static string FormatServiceDescription(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("ServiceDescription"), p0); - /// - /// Missing required option '--{0}' or '--{1}'. - /// - internal static string MissingOptions - { - get => GetString("MissingOptions"); - } - - /// - /// Missing required option '--{0}' or '--{1}'. - /// - internal static string FormatMissingOptions(object p0, object p1) - => string.Format(CultureInfo.CurrentCulture, GetString("MissingOptions"), p0, p1); - /// /// The name of the document to pass to the '--method' method. Default value '{0}'. /// @@ -304,20 +192,6 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static string FormatUsingService(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("UsingService"), p0); - /// - /// Using URI '{0}'. - /// - internal static string UsingUri - { - get => GetString("UsingUri"); - } - - /// - /// Using URI '{0}'. - /// - internal static string FormatUsingUri(object p0) - => string.Format(CultureInfo.CurrentCulture, GetString("UsingUri"), p0); - /// /// Method '{0}' of service '{1}' failed to generate document '{2}'. /// diff --git a/src/GetDocumentInsider/Resources.resx b/src/GetDocumentInsider/Resources.resx index f42b6144e6..fffabb44f3 100644 --- a/src/GetDocumentInsider/Resources.resx +++ b/src/GetDocumentInsider/Resources.resx @@ -120,9 +120,6 @@ The assembly to use. - - Show JSON output. - Missing required option '--{0}'. @@ -135,39 +132,18 @@ Prefix console output with logging level. - - Using application base '{0}'. - - - Using assembly '{0}'. - - - Using configuration file '{0}'. - Show verbose output. - - Writing '{0}'... - - - Using working directory '{0}'. - Location from which inside man was copied (in the .NET Framework case) or loaded. - - The URI to download the document from. - The name of the method to invoke on the '--service' instance. Default value '{0}'. The qualified name of the service type to retrieve from dependency injection. Default value '{0}'. - - Missing required option '--{0}' or '--{1}'. - The name of the document to pass to the '--method' method. Default value '{0}'. @@ -180,13 +156,10 @@ Using service '{0}'. - - Using URI '{0}'. - Method '{0}' of service '{1}' failed to generate document '{2}'. Assembly '{0}' does not contain an entry point. - + \ No newline at end of file diff --git a/src/GetDocumentInsider/WrappedException.cs b/src/GetDocumentInsider/WrappedException.cs deleted file mode 100644 index ec90fb6061..0000000000 --- a/src/GetDocumentInsider/WrappedException.cs +++ /dev/null @@ -1,24 +0,0 @@ -// 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.Client -{ - internal class WrappedException : Exception - { - private readonly string _stackTrace; - - public WrappedException(string type, string message, string stackTrace) - : base(message) - { - Type = type; - _stackTrace = stackTrace; - } - - public string Type { get; } - - public override string ToString() - => _stackTrace; - } -} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs index 1e79fd9722..14c5545b2b 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs +++ b/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs @@ -4,6 +4,9 @@ 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; @@ -94,19 +97,130 @@ namespace Microsoft.Extensions.ApiDescription.Client return; } - log.LogMessage($"Downloading '{uri}' to '{destinationPath}'."); + log.LogMessage(MessageImportance.High, $"Downloading '{uri}' to '{destinationPath}'."); - using (var httpClient = new HttpClient + 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 { - await DownloadFileCore.DownloadAsync( - uri, - destinationPath, - httpClient, - new LogWrapper(log), - cancellationToken, - timeoutSeconds); + 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); } } } diff --git a/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs b/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs deleted file mode 100644 index f058620621..0000000000 --- a/src/Microsoft.Extensions.ApiDescription.Client/LogWrapper.cs +++ /dev/null @@ -1,38 +0,0 @@ -// 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.Build.Utilities; - -namespace Microsoft.Extensions.ApiDescription.Client -{ - internal class LogWrapper : ILogWrapper - { - private readonly TaskLoggingHelper _log; - - public LogWrapper(TaskLoggingHelper log) - { - _log = log; - } - - public void LogError(string message, params object[] messageArgs) - { - _log.LogError(message, messageArgs); - } - - public void LogError(Exception exception, bool showStackTrace) - { - _log.LogErrorFromException(exception, showStackTrace); - } - - public void LogInformational(string message, params object[] messageArgs) - { - _log.LogMessage(message, messageArgs); - } - - public void LogWarning(string message, params object[] messageArgs) - { - _log.LogWarning(message, messageArgs); - } - } -} diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj index daec0b3b26..946f3d1d16 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj +++ b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj @@ -8,21 +8,52 @@ MSBuild tasks and targets for code generation false - false + false + false + false $(MSBuildProjectName).nuspec - Build Tasks;msbuild;DownloadFile;GetFilenameFromUri;code generation + Build Tasks;MSBuild;Swagger;Open API;code generation; Web API client netstandard2.0;net461 - - - + + - - - + + + $(AssemblySigningCertName) + tasks/$(TargetFramework)/$(TargetFileName) + $(AssemblySigningStrongName) + + + + + + + $(AssemblySigningCertName) + tools/dotnet-getdocument.dll + $(AssemblySigningStrongName) + + + $(AssemblySigningCertName) + tools/net461/GetDocument.Insider.exe + $(AssemblySigningStrongName) + + + $(AssemblySigningCertName) + tools/net461-x86/GetDocument.Insider.exe + $(AssemblySigningStrongName) + + + $(AssemblySigningCertName) + tools/netcoreapp2.0/GetDocument.Insider.exe + $(AssemblySigningStrongName) + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec index 5b840bd379..e35a37d51c 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec +++ b/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec @@ -12,17 +12,19 @@ $owners$ $projectUrl$ - false + true $tags$ $version$ - - - - - - + + + + + + + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets b/src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets deleted file mode 100644 index 5ed88a3f6c..0000000000 --- a/src/Microsoft.Extensions.ApiDescription.Client/ServiceProjectReferenceMetadata.targets +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props index d01b8044e8..0e1260da7c 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props @@ -93,11 +93,6 @@ Default is set in server project, falling back to "Microsoft.Extensions.ApiDescription.IDocumentProvider". --> - - diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets index e7c60f9017..051922a579 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets +++ b/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets @@ -179,7 +179,7 @@ - dotnet getdocument --no-build --project %(FullPath) --output %(DocumentPath) + dotnet $(MSBuildThisFileDirectory)/../tools/dotnet-getdocument.dll --project %(FullPath) --output %(DocumentPath) $(DefaultDocumentGeneratorDefaultOptions) %(Command) --service %(Service) - - %(Command) --uri %(Uri) - %(Command) --configuration %(ProjectConfiguration) %(DefaultDocumentGeneratorOptions) diff --git a/src/dotnet-getdocument/Commands/InvokeCommand.cs b/src/dotnet-getdocument/Commands/InvokeCommand.cs index b376b3b9d2..b1426c057d 100644 --- a/src/dotnet-getdocument/Commands/InvokeCommand.cs +++ b/src/dotnet-getdocument/Commands/InvokeCommand.cs @@ -159,12 +159,6 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands args.Add(project.DefaultService); } - if (!(args.Contains("--uri") || string.IsNullOrEmpty(project.DefaultUri))) - { - args.Add("--uri"); - args.Add(project.DefaultUri); - } - if (_output.HasValue()) { args.Add("--output"); diff --git a/src/dotnet-getdocument/Project.cs b/src/dotnet-getdocument/Project.cs index ce3325b7e8..f9fc0da93e 100644 --- a/src/dotnet-getdocument/Project.cs +++ b/src/dotnet-getdocument/Project.cs @@ -1,6 +1,7 @@ // 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; @@ -11,7 +12,8 @@ namespace Microsoft.Extensions.ApiDescription.Client { internal class Project { - private const string MSBuildResourceName = "Microsoft.Extensions.ApiDescription.Client.ServiceProjectReferenceMetadata"; + private const string ResourceFilename = "ServiceProjectReferenceMetadata.targets"; + private const string MSBuildResourceName = "Microsoft.Extensions.ApiDescription.Client." + ResourceFilename; private Project() { @@ -33,8 +35,6 @@ namespace Microsoft.Extensions.ApiDescription.Client public string DefaultService { get; private set; } - public string DefaultUri { get; private set; } - public string DepsPath { get; private set; } public string Directory { get; private set; } @@ -53,41 +53,36 @@ namespace Microsoft.Extensions.ApiDescription.Client 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 static Project FromFile( - string file, + string projectFile, string buildExtensionsDirectory, string framework = null, string configuration = null, string runtime = null) { - Debug.Assert(!string.IsNullOrEmpty(file), "file is null or empty."); + if (string.IsNullOrEmpty(projectFile)) + { + throw new ArgumentNullException(nameof(projectFile)); + } if (string.IsNullOrEmpty(buildExtensionsDirectory)) { - buildExtensionsDirectory = Path.Combine(Path.GetDirectoryName(file), "obj"); + buildExtensionsDirectory = Path.Combine(Path.GetDirectoryName(projectFile), "obj"); } IODirectory.CreateDirectory(buildExtensionsDirectory); var assembly = typeof(Project).Assembly; - var propsPath = Path.Combine( + var targetsPath = Path.Combine( buildExtensionsDirectory, - Path.GetFileName(file) + ".ServiceProjectReferenceMetadata.props"); - using (var input = assembly.GetManifestResourceStream($"{MSBuildResourceName}.props")) - { - using (var output = File.OpenWrite(propsPath)) - { - Reporter.WriteVerbose(Resources.FormatWritingFile(propsPath)); - input.CopyTo(output); - } - } - - var targetsPath = Path.ChangeExtension(propsPath, ".targets"); - using (var input = assembly.GetManifestResourceStream($"{MSBuildResourceName}.targets")) + $"{Path.GetFileName(projectFile)}.{ResourceFilename}"); + using (var input = assembly.GetManifestResourceStream(MSBuildResourceName)) { using (var output = File.OpenWrite(targetsPath)) { @@ -101,32 +96,29 @@ namespace Microsoft.Extensions.ApiDescription.Client var metadataPath = Path.GetTempFileName(); try { - var propertyArg = "/property:ServiceProjectReferenceMetadataPath=" + metadataPath; - if (!string.IsNullOrEmpty(framework)) - { - propertyArg += ";TargetFramework=" + framework; - } - if (!string.IsNullOrEmpty(configuration)) - { - propertyArg += ";Configuration=" + configuration; - } - if (!string.IsNullOrEmpty(runtime)) - { - propertyArg += ";RuntimeIdentifier=" + runtime; - } - var args = new List { "msbuild", "/target:WriteServiceProjectReferenceMetadata", - propertyArg, "/verbosity:quiet", - "/nologo" + "/nologo", + $"/property:ServiceProjectReferenceMetadataPath={metadataPath}", + projectFile, }; - if (!string.IsNullOrEmpty(file)) + if (!string.IsNullOrEmpty(framework)) { - args.Add(file); + 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); @@ -140,21 +132,20 @@ namespace Microsoft.Extensions.ApiDescription.Client } finally { - File.Delete(propsPath); 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)], AssemblyPath = metadata[nameof(AssemblyPath)], AssetsPath = metadata[nameof(AssetsPath)], Configuration = metadata[nameof(Configuration)], - DefaultDocumentName = metadata[nameof(DefaultDocumentName)], - DefaultMethod = metadata[nameof(DefaultMethod)], - DefaultService = metadata[nameof(DefaultService)], - DefaultUri = metadata[nameof(DefaultUri)], DepsPath = metadata[nameof(DepsPath)], Directory = metadata[nameof(Directory)], ExtensionsPath = metadata[nameof(ExtensionsPath)], @@ -164,6 +155,7 @@ namespace Microsoft.Extensions.ApiDescription.Client PlatformTarget = metadata[nameof(PlatformTarget)] ?? metadata[nameof(Platform)], RuntimeConfigPath = metadata[nameof(RuntimeConfigPath)], RuntimeFrameworkVersion = metadata[nameof(RuntimeFrameworkVersion)], + RuntimeIdentifier = metadata[nameof(RuntimeIdentifier)], TargetFramework = metadata[nameof(TargetFramework)], TargetFrameworkMoniker = metadata[nameof(TargetFrameworkMoniker)], }; @@ -193,6 +185,11 @@ namespace Microsoft.Extensions.ApiDescription.Client project.AssemblyPath = Path.GetFullPath(Path.Combine(project.Directory, project.AssemblyPath)); } + if (!Path.IsPathRooted(project.ExtensionsPath)) + { + project.ExtensionsPath = Path.GetFullPath(Path.Combine(project.Directory, project.ExtensionsPath)); + } + if (!Path.IsPathRooted(project.OutputPath)) { project.OutputPath = Path.GetFullPath(Path.Combine(project.Directory, project.OutputPath)); diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.cs b/src/dotnet-getdocument/Properties/Resources.Designer.cs index eb38ce67a7..8ab2cece4f 100644 --- a/src/dotnet-getdocument/Properties/Resources.Designer.cs +++ b/src/dotnet-getdocument/Properties/Resources.Designer.cs @@ -277,7 +277,7 @@ namespace Microsoft.Extensions.ApiDescription.Client => string.Format(CultureInfo.CurrentCulture, GetString("WritingFile"), p0); /// - /// Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + /// Project output not found. Project must be up-to-date when using this tool. /// internal static string MustBuild { @@ -285,7 +285,7 @@ namespace Microsoft.Extensions.ApiDescription.Client } /// - /// Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + /// Project output not found. Project must be up-to-date when using this tool. /// internal static string FormatMustBuild() => GetString("MustBuild"); diff --git a/src/dotnet-getdocument/Resources.resx b/src/dotnet-getdocument/Resources.resx index 7db5873e7d..9829182dc6 100644 --- a/src/dotnet-getdocument/Resources.resx +++ b/src/dotnet-getdocument/Resources.resx @@ -175,7 +175,7 @@ Writing '{0}'... - Project output not found and --no-build was specified. Project must be up-to-date when using the --no-build option. + Project output not found. Project must be up-to-date when using this tool. The file to write the result to. diff --git a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.props b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.props deleted file mode 100644 index 30f045f3c0..0000000000 --- a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - $(WriteServiceProjectReferenceMetadataDependsOn) - - - - - $(WriteServiceProjectReferenceMetadataDependsOn) - - - $(WriteServiceProjectReferenceMetadataDependsOn) - - - diff --git a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets index e8840ea37b..a9a3115b94 100644 --- a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets +++ b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets @@ -1,20 +1,14 @@  - - - + - - - + + @@ -29,21 +23,21 @@ + - - + + - + diff --git a/src/dotnet-getdocument/dotnet-getdocument.csproj b/src/dotnet-getdocument/dotnet-getdocument.csproj index 53967535a7..370514484b 100644 --- a/src/dotnet-getdocument/dotnet-getdocument.csproj +++ b/src/dotnet-getdocument/dotnet-getdocument.csproj @@ -1,89 +1,25 @@ - - $(GenerateNuspecDependsOn);PopulateNuspec - dotnet-getdocument GetDocument Command-line Tool outside man false - true - false false - $(MSBuildProjectName).nuspec Exe - true - GetDocument;command line;command-line;tool Microsoft.Extensions.ApiDescription.Client netcoreapp2.1 - - - + - - - - + - - - - - - - - - - - - - - - <_Temporary Remove="@(Temporary)" /> - <_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=net461" /> - <_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=net461;Platform=x86" /> - <_Temporary Include="../GetDocumentInsider/GetDocumentInsider.csproj" Properties="TargetFramework=netcoreapp2.0" /> - - - - - - - <_Temporary Remove="@(_Temporary)" /> - - - - - authors=$(Authors); - copyright=$(Copyright); - description=$(Description); - iconUrl=$(PackageIconUrl); - id=$(PackageId); - InsiderNet461Output=..\GetDocumentInsider\bin\$(Configuration)\net461\publish\*; - InsiderNet461X86Output=..\GetDocumentInsider\bin\x86\$(Configuration)\net461\publish\*; - InsiderNetCoreOutput=..\GetDocumentInsider\bin\$(Configuration)\netcoreapp2.0\publish\*; - licenseUrl=$(PackageLicenseUrl); - Output=$(PublishDir)**\*; - OutputShims=$(IntermediateOutputPath)shims\**\*; - packageType=$(PackageType); - projectUrl=$(PackageProjectUrl); - repositoryCommit=$(RepositoryCommit); - repositoryUrl=$(RepositoryUrl); - SettingsFile=$(_ToolsSettingsFilePath); - tags=$(PackageTags.Replace(';', ' ')); - targetFramework=$(TargetFramework); - version=$(PackageVersion); - - - diff --git a/src/dotnet-getdocument/dotnet-getdocument.nuspec b/src/dotnet-getdocument/dotnet-getdocument.nuspec deleted file mode 100644 index 60c51f7869..0000000000 --- a/src/dotnet-getdocument/dotnet-getdocument.nuspec +++ /dev/null @@ -1,28 +0,0 @@ - - - - $id$ - $version$ - $authors$ - true - $licenseUrl$ - $projectUrl$ - $iconUrl$ - $description$ - $copyright$ - $tags$ - - - - - - - - - - - - - - - From 5cd86977eda1d06e6619e3f75bded8ee40761a2c Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Sat, 6 Oct 2018 20:07:49 -0700 Subject: [PATCH 13/14] Rename client code generation components - #8523 - main project / package --> `Microsoft.Extensions.ApiDescription.Design` - tasks assembly and namespace --> `Microsoft.Extensions.ApiDescription.Tasks` - tool namespace --> `Microsoft.Extensions.ApiDescription.Tool` - targets --> verbs e.g. `GenerateTypeScriptNSwag` and `GenerateDocumentDefault` - `@(ServiceProjectReference)` metadata -> align with common MSBuild project properties - exception: `$(MSBuildProjectExtensionsPath)`; it's readonly and `%(ProjectExtensionsPath)` is unambiguous - use `%(ProjectExtensionsPath)` - also add `%(Targets)` metadata and remove unused `%(ProjectRuntimeIdentifier)` - `@( align with MSBuild project properties - exceptions: `$(MSBuildProjectDirectory)`, `$(MSBuildProjectExtensionsPath)` and `$(MSBuildProjectName)` - readonly properties and names already unambiguous --- Mvc.NoFun.sln | 2 +- Mvc.sln | 2 +- NuGetPackageVerifier.json | 2 +- src/GetDocumentInsider/AnsiConsole.cs | 2 +- src/GetDocumentInsider/AnsiConstants.cs | 2 +- src/GetDocumentInsider/AnsiTextWriter.cs | 2 +- src/GetDocumentInsider/CommandException.cs | 2 +- .../Commands/CommandBase.cs | 2 +- .../Commands/GetDocumentCommand.cs | 2 +- .../Commands/GetDocumentCommandContext.cs | 2 +- .../Commands/GetDocumentCommandWorker.cs | 2 +- .../Commands/HelpCommandBase.cs | 2 +- .../Commands/ProjectCommandBase.cs | 2 +- .../GetDocumentInsider.csproj | 2 +- src/GetDocumentInsider/ProductInfo.cs | 2 +- src/GetDocumentInsider/Program.cs | 4 +- .../Properties/Resources.Designer.cs | 4 +- src/GetDocumentInsider/Reporter.cs | 4 +- .../DownloadFile.cs | 2 +- .../GetCurrentItems.cs | 2 +- .../GetFileReferenceMetadata.cs | 2 +- .../GetProjectReferenceMetadata.cs | 2 +- .../GetUriReferenceMetadata.cs | 2 +- .../MetadataSerializer.cs | 2 +- ...t.Extensions.ApiDescription.Design.csproj} | 3 + ...t.Extensions.ApiDescription.Design.nuspec} | 4 +- .../Properties/Resources.Designer.cs | 4 +- .../Resources.resx | 0 ...ft.Extensions.ApiDescription.Design.props} | 53 ++++--- ....Extensions.ApiDescription.Design.targets} | 149 +++++++++--------- ....Extensions.ApiDescription.Design.targets} | 4 +- .../Commands/InvokeCommand.cs | 40 ++--- src/dotnet-getdocument/Exe.cs | 2 +- src/dotnet-getdocument/Program.cs | 4 +- src/dotnet-getdocument/Project.cs | 113 +++++++------ src/dotnet-getdocument/ProjectOptions.cs | 18 ++- .../Properties/Resources.Designer.cs | 24 +-- src/dotnet-getdocument/Resources.resx | 8 +- .../ServiceProjectReferenceMetadata.targets | 16 +- .../dotnet-getdocument.csproj | 2 +- 40 files changed, 266 insertions(+), 232 deletions(-) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/DownloadFile.cs (99%) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/GetCurrentItems.cs (94%) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/GetFileReferenceMetadata.cs (98%) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/GetProjectReferenceMetadata.cs (98%) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/GetUriReferenceMetadata.cs (98%) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/MetadataSerializer.cs (99%) rename src/{Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj => Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj} (95%) rename src/{Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec => Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec} (92%) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/Properties/Resources.Designer.cs (96%) rename src/{Microsoft.Extensions.ApiDescription.Client => Microsoft.Extensions.ApiDescription.Design}/Resources.resx (100%) rename src/{Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props => Microsoft.Extensions.ApiDescription.Design/build/Microsoft.Extensions.ApiDescription.Design.props} (71%) rename src/{Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.targets => Microsoft.Extensions.ApiDescription.Design/build/Microsoft.Extensions.ApiDescription.Design.targets} (65%) rename src/{Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets => Microsoft.Extensions.ApiDescription.Design/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Design.targets} (67%) diff --git a/Mvc.NoFun.sln b/Mvc.NoFun.sln index 0167992a7f..d67abd6f60 100644 --- a/Mvc.NoFun.sln +++ b/Mvc.NoFun.sln @@ -121,7 +121,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\d EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client", "src\Microsoft.Extensions.ApiDescription.Client\Microsoft.Extensions.ApiDescription.Client.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}" +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 GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Mvc.sln b/Mvc.sln index ce10a95245..dcd83f09ca 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -182,7 +182,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-getdocument", "src\d EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GetDocumentInsider", "src\GetDocumentInsider\GetDocumentInsider.csproj", "{2F683CF8-B055-46AE-BF83-9D1307F8D45F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.ApiDescription.Client", "src\Microsoft.Extensions.ApiDescription.Client\Microsoft.Extensions.ApiDescription.Client.csproj", "{34E3C302-B767-40C8-B538-3EE2BD4000C4}" +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 GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index 079b7cef51..a1e9573ee3 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -4,7 +4,7 @@ "DefaultCompositeRule" ], "packages": { - "Microsoft.Extensions.ApiDescription.Client": { + "Microsoft.Extensions.ApiDescription.Design": { "Exclusions": { "BUILD_ITEMS_FRAMEWORK": { "*": "Package includes tool with different target frameworks." diff --git a/src/GetDocumentInsider/AnsiConsole.cs b/src/GetDocumentInsider/AnsiConsole.cs index c3f514bde4..306b4ff452 100644 --- a/src/GetDocumentInsider/AnsiConsole.cs +++ b/src/GetDocumentInsider/AnsiConsole.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal class AnsiConsole { diff --git a/src/GetDocumentInsider/AnsiConstants.cs b/src/GetDocumentInsider/AnsiConstants.cs index 48f9ca2410..b54e15b751 100644 --- a/src/GetDocumentInsider/AnsiConstants.cs +++ b/src/GetDocumentInsider/AnsiConstants.cs @@ -1,7 +1,7 @@ // 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.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal static class AnsiConstants { diff --git a/src/GetDocumentInsider/AnsiTextWriter.cs b/src/GetDocumentInsider/AnsiTextWriter.cs index 471d9cf124..066f711e27 100644 --- a/src/GetDocumentInsider/AnsiTextWriter.cs +++ b/src/GetDocumentInsider/AnsiTextWriter.cs @@ -6,7 +6,7 @@ using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal class AnsiTextWriter { diff --git a/src/GetDocumentInsider/CommandException.cs b/src/GetDocumentInsider/CommandException.cs index 18680f9593..c1437b038b 100644 --- a/src/GetDocumentInsider/CommandException.cs +++ b/src/GetDocumentInsider/CommandException.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal class CommandException : Exception { diff --git a/src/GetDocumentInsider/Commands/CommandBase.cs b/src/GetDocumentInsider/Commands/CommandBase.cs index 5ca14744cb..ac9a4b1a37 100644 --- a/src/GetDocumentInsider/Commands/CommandBase.cs +++ b/src/GetDocumentInsider/Commands/CommandBase.cs @@ -3,7 +3,7 @@ using Microsoft.DotNet.Cli.CommandLine; -namespace Microsoft.Extensions.ApiDescription.Client.Commands +namespace Microsoft.Extensions.ApiDescription.Tool.Commands { internal abstract class CommandBase { diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs index cd45255f09..bf80df802b 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommand.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommand.cs @@ -10,7 +10,7 @@ using System.Runtime.Loader; #endif using Microsoft.DotNet.Cli.CommandLine; -namespace Microsoft.Extensions.ApiDescription.Client.Commands +namespace Microsoft.Extensions.ApiDescription.Tool.Commands { internal class GetDocumentCommand : ProjectCommandBase { diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs index c4fc0b6e45..208139c12f 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandContext.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.Extensions.ApiDescription.Client.Commands +namespace Microsoft.Extensions.ApiDescription.Tool.Commands { [Serializable] public class GetDocumentCommandContext diff --git a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs index b0434e453c..752d65861f 100644 --- a/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs +++ b/src/GetDocumentInsider/Commands/GetDocumentCommandWorker.cs @@ -7,7 +7,7 @@ using System.Reflection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.Extensions.ApiDescription.Client.Commands +namespace Microsoft.Extensions.ApiDescription.Tool.Commands { internal class GetDocumentCommandWorker { diff --git a/src/GetDocumentInsider/Commands/HelpCommandBase.cs b/src/GetDocumentInsider/Commands/HelpCommandBase.cs index 3f80564d54..55e84272ac 100644 --- a/src/GetDocumentInsider/Commands/HelpCommandBase.cs +++ b/src/GetDocumentInsider/Commands/HelpCommandBase.cs @@ -3,7 +3,7 @@ using Microsoft.DotNet.Cli.CommandLine; -namespace Microsoft.Extensions.ApiDescription.Client.Commands +namespace Microsoft.Extensions.ApiDescription.Tool.Commands { internal class HelpCommandBase : CommandBase { diff --git a/src/GetDocumentInsider/Commands/ProjectCommandBase.cs b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs index 7e6e49c750..8e60d9603f 100644 --- a/src/GetDocumentInsider/Commands/ProjectCommandBase.cs +++ b/src/GetDocumentInsider/Commands/ProjectCommandBase.cs @@ -3,7 +3,7 @@ using Microsoft.DotNet.Cli.CommandLine; -namespace Microsoft.Extensions.ApiDescription.Client.Commands +namespace Microsoft.Extensions.ApiDescription.Tool.Commands { internal abstract class ProjectCommandBase : HelpCommandBase { diff --git a/src/GetDocumentInsider/GetDocumentInsider.csproj b/src/GetDocumentInsider/GetDocumentInsider.csproj index b2c4fed5c6..03d6440c1f 100644 --- a/src/GetDocumentInsider/GetDocumentInsider.csproj +++ b/src/GetDocumentInsider/GetDocumentInsider.csproj @@ -4,7 +4,7 @@ GetDocument Command-line Tool inside man false Exe - Microsoft.Extensions.ApiDescription.Client + Microsoft.Extensions.ApiDescription.Tool netcoreapp2.0;net461 diff --git a/src/GetDocumentInsider/ProductInfo.cs b/src/GetDocumentInsider/ProductInfo.cs index 8db001423a..c57bc65d10 100644 --- a/src/GetDocumentInsider/ProductInfo.cs +++ b/src/GetDocumentInsider/ProductInfo.cs @@ -3,7 +3,7 @@ using System.Reflection; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal static class ProductInfo { diff --git a/src/GetDocumentInsider/Program.cs b/src/GetDocumentInsider/Program.cs index af1bdc298a..6d144dc5d5 100644 --- a/src/GetDocumentInsider/Program.cs +++ b/src/GetDocumentInsider/Program.cs @@ -4,9 +4,9 @@ using System; using System.Text; using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Commands; +using Microsoft.Extensions.ApiDescription.Tool.Commands; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal static class Program { diff --git a/src/GetDocumentInsider/Properties/Resources.Designer.cs b/src/GetDocumentInsider/Properties/Resources.Designer.cs index c9576ef8c0..eaec18f2fe 100644 --- a/src/GetDocumentInsider/Properties/Resources.Designer.cs +++ b/src/GetDocumentInsider/Properties/Resources.Designer.cs @@ -1,5 +1,5 @@ // -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { using System.Globalization; using System.Reflection; @@ -8,7 +8,7 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.Extensions.ApiDescription.Tool.Resources", typeof(Resources).GetTypeInfo().Assembly); /// /// The assembly to use. diff --git a/src/GetDocumentInsider/Reporter.cs b/src/GetDocumentInsider/Reporter.cs index abfec580fb..9a589fcc67 100644 --- a/src/GetDocumentInsider/Reporter.cs +++ b/src/GetDocumentInsider/Reporter.cs @@ -3,9 +3,9 @@ using System; using System.Linq; -using static Microsoft.Extensions.ApiDescription.Client.AnsiConstants; +using static Microsoft.Extensions.ApiDescription.Tool.AnsiConstants; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal static class Reporter { diff --git a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs b/src/Microsoft.Extensions.ApiDescription.Design/DownloadFile.cs similarity index 99% rename from src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs rename to src/Microsoft.Extensions.ApiDescription.Design/DownloadFile.cs index 14c5545b2b..177f405ea1 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/DownloadFile.cs +++ b/src/Microsoft.Extensions.ApiDescription.Design/DownloadFile.cs @@ -14,7 +14,7 @@ using Microsoft.Build.Utilities; using Task = System.Threading.Tasks.Task; using Utilities = Microsoft.Build.Utilities; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tasks { /// /// Downloads a file. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetCurrentItems.cs b/src/Microsoft.Extensions.ApiDescription.Design/GetCurrentItems.cs similarity index 94% rename from src/Microsoft.Extensions.ApiDescription.Client/GetCurrentItems.cs rename to src/Microsoft.Extensions.ApiDescription.Design/GetCurrentItems.cs index 975e716d64..97ea236f2c 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetCurrentItems.cs +++ b/src/Microsoft.Extensions.ApiDescription.Design/GetCurrentItems.cs @@ -4,7 +4,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tasks { /// /// Restore s from given property value. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Design/GetFileReferenceMetadata.cs similarity index 98% rename from src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs rename to src/Microsoft.Extensions.ApiDescription.Design/GetFileReferenceMetadata.cs index 54ae8b7500..70ac4d847f 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetFileReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Design/GetFileReferenceMetadata.cs @@ -7,7 +7,7 @@ using System.IO; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tasks { /// /// Adds or corrects ClassName, Namespace and OutputPath metadata in ServiceFileReference items. Also stores final diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Design/GetProjectReferenceMetadata.cs similarity index 98% rename from src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs rename to src/Microsoft.Extensions.ApiDescription.Design/GetProjectReferenceMetadata.cs index 0c682107e5..a4ad42abe7 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetProjectReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Design/GetProjectReferenceMetadata.cs @@ -6,7 +6,7 @@ using System.IO; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tasks { /// /// Adds or corrects DocumentPath and project-related metadata in ServiceProjectReference items. Also stores final diff --git a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs b/src/Microsoft.Extensions.ApiDescription.Design/GetUriReferenceMetadata.cs similarity index 98% rename from src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs rename to src/Microsoft.Extensions.ApiDescription.Design/GetUriReferenceMetadata.cs index 6870d2a337..922359cb36 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/GetUriReferenceMetadata.cs +++ b/src/Microsoft.Extensions.ApiDescription.Design/GetUriReferenceMetadata.cs @@ -7,7 +7,7 @@ using System.IO; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tasks { /// /// Adds or corrects DocumentPath metadata in ServiceUriReference items. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/MetadataSerializer.cs b/src/Microsoft.Extensions.ApiDescription.Design/MetadataSerializer.cs similarity index 99% rename from src/Microsoft.Extensions.ApiDescription.Client/MetadataSerializer.cs rename to src/Microsoft.Extensions.ApiDescription.Design/MetadataSerializer.cs index 3f430380a0..331bac617a 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/MetadataSerializer.cs +++ b/src/Microsoft.Extensions.ApiDescription.Design/MetadataSerializer.cs @@ -6,7 +6,7 @@ using System.Text; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tasks { /// /// Utility methods to serialize and deserialize metadata. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj similarity index 95% rename from src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj rename to src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj index 946f3d1d16..164a547cc4 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.csproj +++ b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj @@ -6,13 +6,16 @@ true + Microsoft.Extensions.ApiDescription.Tasks MSBuild tasks and targets for code generation false false false false $(MSBuildProjectName).nuspec + $(MSBuildProjectName) Build Tasks;MSBuild;Swagger;Open API;code generation; Web API client + $(AssemblyName) netstandard2.0;net461 diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec similarity index 92% rename from src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec rename to src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec index e35a37d51c..95ca2bcfd8 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Microsoft.Extensions.ApiDescription.Client.nuspec +++ b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec @@ -20,8 +20,8 @@ - - + + diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Properties/Resources.Designer.cs b/src/Microsoft.Extensions.ApiDescription.Design/Properties/Resources.Designer.cs similarity index 96% rename from src/Microsoft.Extensions.ApiDescription.Client/Properties/Resources.Designer.cs rename to src/Microsoft.Extensions.ApiDescription.Design/Properties/Resources.Designer.cs index 27049a4842..b72e347e21 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/Properties/Resources.Designer.cs +++ b/src/Microsoft.Extensions.ApiDescription.Design/Properties/Resources.Designer.cs @@ -1,5 +1,5 @@ // -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tasks { using System.Globalization; using System.Reflection; @@ -8,7 +8,7 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.Extensions.ApiDescription.Tasks.Resources", typeof(Resources).GetTypeInfo().Assembly); /// /// Multiple items have OutputPath='{0}'. All ServiceFileReference, ServiceProjectReference and ServiceUriReference items must have unique OutputPath metadata. diff --git a/src/Microsoft.Extensions.ApiDescription.Client/Resources.resx b/src/Microsoft.Extensions.ApiDescription.Design/Resources.resx similarity index 100% rename from src/Microsoft.Extensions.ApiDescription.Client/Resources.resx rename to src/Microsoft.Extensions.ApiDescription.Design/Resources.resx diff --git a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props b/src/Microsoft.Extensions.ApiDescription.Design/build/Microsoft.Extensions.ApiDescription.Design.props similarity index 71% rename from src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props rename to src/Microsoft.Extensions.ApiDescription.Design/build/Microsoft.Extensions.ApiDescription.Design.props index 0e1260da7c..3a3177cdc9 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/build/Microsoft.Extensions.ApiDescription.Client.props +++ b/src/Microsoft.Extensions.ApiDescription.Design/build/Microsoft.Extensions.ApiDescription.Design.props @@ -1,16 +1,19 @@  - <_ApiDescriptionTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 - <_ApiDescriptionTasksAssemblyTarget Condition="'$(MSBuildRuntimeType)' != 'Core'">net461 - <_ApiDescriptionTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_ApiDescriptionTasksAssemblyTarget)/Microsoft.Extensions.ApiDescription.Client.dll + <_ApiDescriptionTasksAssemblyTarget + Condition="'$(MSBuildRuntimeType)' == 'Core'">netstandard2.0 + <_ApiDescriptionTasksAssemblyTarget + Condition="'$(MSBuildRuntimeType)' != 'Core'">net461 + <_ApiDescriptionTasksAssemblyPath>$(MSBuildThisFileDirectory)/../tasks/$(_ApiDescriptionTasksAssemblyTarget)/Microsoft.Extensions.ApiDescription.Tasks.dll <_ApiDescriptionTasksAssemblyTarget /> - + Default - - - + - - - - + + + + + + - + - + - - _ServiceProjectReferenceGenerator_GetTargetFramework; - _ServiceProjectReferenceGenerator_GetProjectTargetPath; - _ServiceProjectReferenceGenerator_GetMetadata; - _ServiceProjectReferenceGenerator_Build; - _ServiceProjectReferenceGenerator_Core; - _ServiceProjectReferenceGenerator_SetMetadata - - - _ServiceUriReferenceGenerator_GetMetadata; - _ServiceUriReferenceGenerator_Core - - - ServiceProjectReferenceGenerator; - ServiceUriReferenceGenerator; - _ServiceFileReferenceGenerator_GetMetadata; - _ServiceFileReferenceGenerator_Core; - _ServiceFileReferenceGenerator_SetMetadata - + + _GetTargetFrameworkForServiceProjectReferences; + _GetTargetPathForServiceProjectReferences; + _GetMetadataForServiceProjectReferences; + _BuildServiceProjectReferences; + _GenerateServiceProjectReferenceDocuments; + _CreateFileItemsForServiceProjectReferences + + + _GetMetadataForServiceUriReferences; + _GenerateServiceUriReferenceDocuments + + + GenerateServiceProjectReferenceDocuments; + GenerateServiceUriReferenceDocuments; + _GetMetadataForServiceFileReferences; + _GenerateServiceFileReferenceCodes; + _CreateCompileItemsForServiceFileReferences + - @@ -56,8 +56,7 @@ - $(_TargetFramework) + $(_TargetFramework) <_Temporary Remove="@(_Temporary)" /> @@ -70,16 +69,16 @@ - <_FullPath>%(ServiceProjectReference.FullPath) - <_TargetFramework>%(ServiceProjectReference.ProjectTargetFramework) + <_TargetFramework>%(ServiceProjectReference.TargetFramework) <_Temporary Remove="@(_Temporary)" /> @@ -95,25 +94,25 @@ - <_ProjectTargetPath>%(_Temporary.FullPath) + <_TargetPath>%(_Temporary.FullPath) - $(_ProjectTargetPath) + Condition="'%(FullPath)' == '$(_FullPath)' AND '%(TargetFramework)' == '$(_TargetFramework)'"> + $(_TargetPath) <_Temporary Remove="@(_Temporary)" /> <_FullPath /> - <_ProjectTargetPath /> + <_TargetPath /> <_TargetFramework /> - + <_Temporary Remove="@(_Temporary)" /> @@ -132,38 +131,40 @@ - + Outputs="%(TargetPath)"> + Targets="%(Targets)" /> - + - + - + + Targets="_GenerateServiceProjectReferenceDocument" /> - - + + - + %(ServiceProjectReference.FullPath) @@ -171,22 +172,22 @@ - + - + - + - dotnet $(MSBuildThisFileDirectory)/../tools/dotnet-getdocument.dll --project %(FullPath) --output %(DocumentPath) - $(DefaultDocumentGeneratorDefaultOptions) - $(Configuration) + dotnet $(MSBuildThisFileDirectory)/../tools/dotnet-getdocument.dll --project %(FullPath) + $(Configuration) + $(GenerateDefaultDocumentDefaultOptions) - %(Command) --framework %(ProjectTargetFramework) + %(Command) --framework %(TargetFramework) --output %(DocumentPath) %(Command) --method %(Method) @@ -195,11 +196,15 @@ %(Command) --service %(Service) - %(Command) --configuration %(ProjectConfiguration) %(DefaultDocumentGeneratorOptions) + %(Command) --projectExtensionsPath %(ProjectExtensionsPath) + + + %(Command) --configuration %(Configuration) %(GenerateDefaultDocumentOptions) - + @@ -207,7 +212,7 @@ - + <_Temporary Remove="@(_Temporary)" /> @@ -223,12 +228,12 @@ - - + - + @@ -237,11 +242,12 @@ - + - + <_Temporary Remove="@(_Temporary)" /> @@ -260,28 +266,27 @@ - + - + - + + Targets="_GenerateServiceFileReferenceCode" /> - + <_Files Remove="@(_Files)" /> @@ -324,7 +329,7 @@ - + DependsOnTargets="$(GenerateServiceFileReferenceCodesDependsOn)" /> diff --git a/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets b/src/Microsoft.Extensions.ApiDescription.Design/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Design.targets similarity index 67% rename from src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets rename to src/Microsoft.Extensions.ApiDescription.Design/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Design.targets index a9c3d53836..af5d08a6bb 100644 --- a/src/Microsoft.Extensions.ApiDescription.Client/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Client.targets +++ b/src/Microsoft.Extensions.ApiDescription.Design/buildMultiTargeting/Microsoft.Extensions.ApiDescription.Design.targets @@ -1,8 +1,8 @@  - + diff --git a/src/dotnet-getdocument/Commands/InvokeCommand.cs b/src/dotnet-getdocument/Commands/InvokeCommand.cs index b1426c057d..4d24919c08 100644 --- a/src/dotnet-getdocument/Commands/InvokeCommand.cs +++ b/src/dotnet-getdocument/Commands/InvokeCommand.cs @@ -10,30 +10,30 @@ using Microsoft.DotNet.Cli.CommandLine; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace Microsoft.Extensions.ApiDescription.Client.Commands +namespace Microsoft.Extensions.ApiDescription.Tool.Commands { internal class InvokeCommand : HelpCommandBase { private const string InsideManName = "GetDocument.Insider"; + private IList _args; private CommandOption _configuration; - private CommandOption _framework; - private CommandOption _msbuildprojectextensionspath; private CommandOption _output; private CommandOption _project; + private CommandOption _projectExtensionsPath; private CommandOption _runtime; - private IList _args; + private CommandOption _targetFramework; public override void Configure(CommandLineApplication command) { var options = new ProjectOptions(); options.Configure(command); - _project = options.Project; - _framework = options.Framework; _configuration = options.Configuration; + _project = options.Project; + _projectExtensionsPath = options.ProjectExtensionsPath; _runtime = options.Runtime; - _msbuildprojectextensionspath = options.MSBuildProjectExtensionsPath; + _targetFramework = options.TargetFramework; _output = command.Option("--output ", Resources.OutputDescription); command.VersionOption("--version", ProductInfo.GetVersion); @@ -52,11 +52,11 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands var project = Project.FromFile( projectFile, - _msbuildprojectextensionspath.Value(), - _framework.Value(), + _projectExtensionsPath.Value(), + _targetFramework.Value(), _configuration.Value(), _runtime.Value()); - if (!File.Exists(project.AssemblyPath)) + if (!File.Exists(project.TargetPath)) { throw new CommandException(Resources.MustBuild); } @@ -95,16 +95,16 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands if (targetFramework.Version < new Version(2, 0)) { throw new CommandException( - Resources.FormatNETCoreApp1Project(project.Name, targetFramework.Version)); + Resources.FormatNETCoreApp1Project(project.ProjectName, targetFramework.Version)); } args.Add("exec"); args.Add("--depsFile"); - args.Add(project.DepsPath); + args.Add(project.ProjectDepsFilePath); - if (!string.IsNullOrEmpty(project.AssetsPath)) + if (!string.IsNullOrEmpty(project.ProjectAssetsFile)) { - using (var reader = new JsonTextReader(File.OpenText(project.AssetsPath))) + using (var reader = new JsonTextReader(File.OpenText(project.ProjectAssetsFile))) { var projectAssets = JToken.ReadFrom(reader); var packageFolders = projectAssets["packageFolders"] @@ -119,10 +119,10 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands } } - if (File.Exists(project.RuntimeConfigPath)) + if (File.Exists(project.ProjectRuntimeConfigFilePath)) { args.Add("--runtimeConfig"); - args.Add(project.RuntimeConfigPath); + args.Add(project.ProjectRuntimeConfigFilePath); } else if (!string.IsNullOrEmpty(project.RuntimeFrameworkVersion)) { @@ -134,16 +134,16 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands break; case ".NETStandard": - throw new CommandException(Resources.FormatNETStandardProject(project.Name)); + throw new CommandException(Resources.FormatNETStandardProject(project.ProjectName)); default: throw new CommandException( - Resources.FormatUnsupportedFramework(project.Name, targetFramework.Identifier)); + Resources.FormatUnsupportedFramework(project.ProjectName, targetFramework.Identifier)); } args.AddRange(_args); args.Add("--assembly"); - args.Add(project.AssemblyPath); + args.Add(project.TargetPath); args.Add("--tools-directory"); args.Add(toolsDirectory); @@ -180,7 +180,7 @@ namespace Microsoft.Extensions.ApiDescription.Client.Commands args.Add("--prefix-output"); } - return Exe.Run(executable, args, project.Directory); + return Exe.Run(executable, args, project.ProjectDirectory); } finally { diff --git a/src/dotnet-getdocument/Exe.cs b/src/dotnet-getdocument/Exe.cs index 32595ce9ab..08fc4217ba 100644 --- a/src/dotnet-getdocument/Exe.cs +++ b/src/dotnet-getdocument/Exe.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Text; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal static class Exe { diff --git a/src/dotnet-getdocument/Program.cs b/src/dotnet-getdocument/Program.cs index 4e1f7fb5ca..94958f2840 100644 --- a/src/dotnet-getdocument/Program.cs +++ b/src/dotnet-getdocument/Program.cs @@ -3,9 +3,9 @@ using System; using Microsoft.DotNet.Cli.CommandLine; -using Microsoft.Extensions.ApiDescription.Client.Commands; +using Microsoft.Extensions.ApiDescription.Tool.Commands; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal static class Program { diff --git a/src/dotnet-getdocument/Project.cs b/src/dotnet-getdocument/Project.cs index f9fc0da93e..dc4a06ea36 100644 --- a/src/dotnet-getdocument/Project.cs +++ b/src/dotnet-getdocument/Project.cs @@ -8,12 +8,12 @@ using System.IO; using System.Linq; using IODirectory = System.IO.Directory; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal class Project { private const string ResourceFilename = "ServiceProjectReferenceMetadata.targets"; - private const string MSBuildResourceName = "Microsoft.Extensions.ApiDescription.Client." + ResourceFilename; + private const string MSBuildResourceName = "Microsoft.Extensions.ApiDescription.Tool." + ResourceFilename; private Project() { @@ -21,35 +21,33 @@ namespace Microsoft.Extensions.ApiDescription.Client public string AssemblyName { get; private set; } - public string AssemblyPath { get; private set; } - - public string AssetsPath { get; private set; } + public string ConfigPath { get; private set; } public string Configuration { get; private set; } - public string ConfigPath { get; private set; } - public string DefaultDocumentName { get; private set; } public string DefaultMethod { get; private set; } public string DefaultService { get; private set; } - public string DepsPath { get; private set; } - - public string Directory { get; private set; } - - public string ExtensionsPath { get; private set; } - - public string Name { get; private set; } - public string OutputPath { get; private set; } public string Platform { get; private set; } public string PlatformTarget { get; private set; } - public string RuntimeConfigPath { get; private set; } + public string 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; } @@ -59,6 +57,8 @@ namespace Microsoft.Extensions.ApiDescription.Client public string TargetFrameworkMoniker { get; private set; } + public string TargetPath { get; private set; } + public static Project FromFile( string projectFile, string buildExtensionsDirectory, @@ -127,7 +127,9 @@ namespace Microsoft.Extensions.ApiDescription.Client throw new CommandException(Resources.GetMetadataFailed); } - metadata = File.ReadLines(metadataPath).Select(l => l.Split(new[] { ':' }, 2)) + metadata = File + .ReadLines(metadataPath) + .Select(l => l.Split(new[] { ':' }, 2)) .ToDictionary(s => s[0], s => s[1].TrimStart()); } finally @@ -143,79 +145,88 @@ namespace Microsoft.Extensions.ApiDescription.Client DefaultService = metadata[nameof(DefaultService)], AssemblyName = metadata[nameof(AssemblyName)], - AssemblyPath = metadata[nameof(AssemblyPath)], - AssetsPath = metadata[nameof(AssetsPath)], Configuration = metadata[nameof(Configuration)], - DepsPath = metadata[nameof(DepsPath)], - Directory = metadata[nameof(Directory)], - ExtensionsPath = metadata[nameof(ExtensionsPath)], - Name = metadata[nameof(Name)], OutputPath = metadata[nameof(OutputPath)], Platform = metadata[nameof(Platform)], PlatformTarget = metadata[nameof(PlatformTarget)] ?? metadata[nameof(Platform)], - RuntimeConfigPath = metadata[nameof(RuntimeConfigPath)], + 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.AssemblyPath)) - { - throw new CommandException(Resources.FormatGetMetadataValueFailed(nameof(AssemblyPath), "TargetPath")); - } - - if (string.IsNullOrEmpty(project.Directory)) - { - throw new CommandException(Resources.FormatGetMetadataValueFailed(nameof(Directory), "ProjectDir")); - } - if (string.IsNullOrEmpty(project.OutputPath)) { - throw new CommandException(Resources.FormatGetMetadataValueFailed(nameof(OutputPath), "OutDir")); + throw new CommandException( + Resources.FormatGetMetadataValueFailed(nameof(OutputPath), nameof(OutputPath))); } - if (!Path.IsPathRooted(project.Directory)) + if (string.IsNullOrEmpty(project.ProjectDirectory)) { - project.Directory = Path.GetFullPath(Path.Combine(IODirectory.GetCurrentDirectory(), project.Directory)); + throw new CommandException( + Resources.FormatGetMetadataValueFailed(nameof(ProjectDirectory), "MSBuildProjectDirectory")); } - if (!Path.IsPathRooted(project.AssemblyPath)) + if (string.IsNullOrEmpty(project.TargetPath)) { - project.AssemblyPath = Path.GetFullPath(Path.Combine(project.Directory, project.AssemblyPath)); + throw new CommandException( + Resources.FormatGetMetadataValueFailed(nameof(TargetPath), nameof(TargetPath))); } - if (!Path.IsPathRooted(project.ExtensionsPath)) + if (!Path.IsPathRooted(project.ProjectDirectory)) { - project.ExtensionsPath = Path.GetFullPath(Path.Combine(project.Directory, project.ExtensionsPath)); + project.OutputPath = Path.GetFullPath( + Path.Combine(IODirectory.GetCurrentDirectory(), project.ProjectDirectory)); } if (!Path.IsPathRooted(project.OutputPath)) { - project.OutputPath = Path.GetFullPath(Path.Combine(project.Directory, project.OutputPath)); + project.OutputPath = Path.GetFullPath(Path.Combine(project.ProjectDirectory, project.OutputPath)); } - // Some document generation tools support non-ASP.NET Core projects. - // Thus any of the remaining properties may be empty. - if (!(string.IsNullOrEmpty(project.AssetsPath) || Path.IsPathRooted(project.AssetsPath))) + if (!Path.IsPathRooted(project.ProjectExtensionsPath)) { - project.AssetsPath = Path.GetFullPath(Path.Combine(project.Directory, project.AssetsPath)); + project.ProjectExtensionsPath = Path.GetFullPath( + Path.Combine(project.ProjectDirectory, project.ProjectExtensionsPath)); } - var configPath = $"{project.AssemblyPath}.config"; + 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.DepsPath) || Path.IsPathRooted(project.DepsPath))) + if (!(string.IsNullOrEmpty(project.ProjectAssetsFile) || Path.IsPathRooted(project.ProjectAssetsFile))) { - project.DepsPath = Path.GetFullPath(Path.Combine(project.Directory, project.DepsPath)); + project.ProjectAssetsFile = Path.GetFullPath( + Path.Combine(project.ProjectDirectory, project.ProjectAssetsFile)); } - if (!(string.IsNullOrEmpty(project.RuntimeConfigPath) || Path.IsPathRooted(project.RuntimeConfigPath))) + if (!(string.IsNullOrEmpty(project.ProjectDepsFilePath) || Path.IsPathRooted(project.ProjectDepsFilePath))) { - project.RuntimeConfigPath = Path.GetFullPath(Path.Combine(project.Directory, project.RuntimeConfigPath)); + 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; diff --git a/src/dotnet-getdocument/ProjectOptions.cs b/src/dotnet-getdocument/ProjectOptions.cs index f3b7d1148e..c235c2191a 100644 --- a/src/dotnet-getdocument/ProjectOptions.cs +++ b/src/dotnet-getdocument/ProjectOptions.cs @@ -3,27 +3,29 @@ using Microsoft.DotNet.Cli.CommandLine; -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { internal class ProjectOptions { + public CommandOption Configuration { get; private set; } + public CommandOption Project { get; private set; } - public CommandOption Framework { get; private set; } - - public CommandOption Configuration { get; private set; } + public CommandOption ProjectExtensionsPath { get; private set; } public CommandOption Runtime { get; private set; } - public CommandOption MSBuildProjectExtensionsPath { get; private set; } + public CommandOption TargetFramework { get; private set; } public void Configure(CommandLineApplication command) { - Project = command.Option("-p|--project ", Resources.ProjectDescription); - Framework = command.Option("--framework ", Resources.FrameworkDescription); Configuration = command.Option("--configuration ", Resources.ConfigurationDescription); + Project = command.Option("-p|--project ", Resources.ProjectDescription); + ProjectExtensionsPath = command.Option( + "--projectExtensionsPath ", + Resources.ProjectExtensionsPathDescription); Runtime = command.Option("--runtime ", Resources.RuntimeDescription); - MSBuildProjectExtensionsPath = command.Option("--msbuildprojectextensionspath ", Resources.ProjectExtensionsDescription); + TargetFramework = command.Option("--framework ", Resources.TargetFrameworkDescription); } } } diff --git a/src/dotnet-getdocument/Properties/Resources.Designer.cs b/src/dotnet-getdocument/Properties/Resources.Designer.cs index 8ab2cece4f..f2b9084ae1 100644 --- a/src/dotnet-getdocument/Properties/Resources.Designer.cs +++ b/src/dotnet-getdocument/Properties/Resources.Designer.cs @@ -1,5 +1,5 @@ // -namespace Microsoft.Extensions.ApiDescription.Client +namespace Microsoft.Extensions.ApiDescription.Tool { using System.Globalization; using System.Reflection; @@ -8,7 +8,7 @@ namespace Microsoft.Extensions.ApiDescription.Client internal static class Resources { private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.Extensions.ApiDescription.Client.Resources", typeof(Resources).GetTypeInfo().Assembly); + = new ResourceManager("Microsoft.Extensions.ApiDescription.Tool.Resources", typeof(Resources).GetTypeInfo().Assembly); /// /// The configuration to use. @@ -41,19 +41,19 @@ namespace Microsoft.Extensions.ApiDescription.Client /// /// The target framework. /// - internal static string FrameworkDescription + internal static string TargetFrameworkDescription { - get => GetString("FrameworkDescription"); + get => GetString("TargetFrameworkDescription"); } /// /// The target framework. /// - internal static string FormatFrameworkDescription() - => GetString("FrameworkDescription"); + internal static string FormatTargetFrameworkDescription() + => GetString("TargetFrameworkDescription"); /// - /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. + /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --projectExtensionsPath option. /// internal static string GetMetadataFailed { @@ -61,7 +61,7 @@ namespace Microsoft.Extensions.ApiDescription.Client } /// - /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. + /// Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --projectExtensionsPath option. /// internal static string FormatGetMetadataFailed() => GetString("GetMetadataFailed"); @@ -195,16 +195,16 @@ namespace Microsoft.Extensions.ApiDescription.Client /// /// The MSBuild project extensions path. Defaults to "obj". /// - internal static string ProjectExtensionsDescription + internal static string ProjectExtensionsPathDescription { - get => GetString("ProjectExtensionsDescription"); + get => GetString("ProjectExtensionsPathDescription"); } /// /// The MSBuild project extensions path. Defaults to "obj". /// - internal static string FormatProjectExtensionsDescription() - => GetString("ProjectExtensionsDescription"); + internal static string FormatProjectExtensionsPathDescription() + => GetString("ProjectExtensionsPathDescription"); /// /// The runtime identifier to use. diff --git a/src/dotnet-getdocument/Resources.resx b/src/dotnet-getdocument/Resources.resx index 9829182dc6..d87157fff2 100644 --- a/src/dotnet-getdocument/Resources.resx +++ b/src/dotnet-getdocument/Resources.resx @@ -123,11 +123,11 @@ dotnet-getdocument - + The target framework. - Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --msbuildprojectextensionspath option. + Unable to retrieve project metadata. If you are using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, use the --projectExtensionsPath option. More than one project was found in the current working directory. Use the --project option. @@ -156,7 +156,7 @@ The project to use. - + The MSBuild project extensions path. Defaults to "obj". @@ -181,6 +181,6 @@ The file to write the result to. - Unable to retrieve '{0}' project metadata. Ensure '{1}' is set. + Unable to retrieve '{0}' project metadata. Ensure '$({1})' is set. diff --git a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets index a9a3115b94..177d950c9e 100644 --- a/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets +++ b/src/dotnet-getdocument/ServiceProjectReferenceMetadata.targets @@ -11,21 +11,21 @@ - - - - - - - + - + + + + + + + diff --git a/src/dotnet-getdocument/dotnet-getdocument.csproj b/src/dotnet-getdocument/dotnet-getdocument.csproj index 370514484b..ebda3eb047 100644 --- a/src/dotnet-getdocument/dotnet-getdocument.csproj +++ b/src/dotnet-getdocument/dotnet-getdocument.csproj @@ -5,7 +5,7 @@ false false Exe - Microsoft.Extensions.ApiDescription.Client + Microsoft.Extensions.ApiDescription.Tool netcoreapp2.1 From 8c58fdb7552288018becdccb9fcc018c597cd1f6 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Thu, 11 Oct 2018 11:32:03 -0700 Subject: [PATCH 14/14] Add Newtonsoft.Json.dll to Microsoft.Extensions.ApiDescription.Design package - also remove dotnet-getdocument.runtimeconfig.dev.json file --- NuGetPackageVerifier.json | 15 +++++++++++++++ ...rosoft.Extensions.ApiDescription.Design.csproj | 12 +++++++++++- ...rosoft.Extensions.ApiDescription.Design.nuspec | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index a1e9573ee3..f551b83476 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -8,6 +8,21 @@ "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" } } } diff --git a/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj index 164a547cc4..593a24fc70 100644 --- a/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj +++ b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.csproj @@ -37,7 +37,7 @@ - + $(AssemblySigningCertName) tools/dotnet-getdocument.dll $(AssemblySigningStrongName) @@ -57,9 +57,19 @@ tools/netcoreapp2.0/GetDocument.Insider.exe $(AssemblySigningStrongName) + + + tools/Newtonsoft.Json.dll" + $(AssemblySigning3rdPartyCertName)" + + + id=$(PackageId); diff --git a/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec index 95ca2bcfd8..e4b8130e5b 100644 --- a/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec +++ b/src/Microsoft.Extensions.ApiDescription.Design/Microsoft.Extensions.ApiDescription.Design.nuspec @@ -22,7 +22,7 @@ - +