11namespace Neolution . DotNet . Console
22{
33 using System ;
4- using System . Collections . Generic ;
5- using System . Linq ;
64 using System . Reflection ;
75 using System . Threading . Tasks ;
86 using CommandLine ;
9- using Microsoft . Extensions . Configuration ;
107 using Microsoft . Extensions . DependencyInjection ;
11- using Microsoft . Extensions . FileProviders ;
128 using Microsoft . Extensions . Hosting ;
13- using Microsoft . Extensions . Logging ;
149 using Neolution . DotNet . Console . Abstractions ;
15- using Neolution . DotNet . Console . Internal ;
16- using NLog . Extensions . Logging ;
1710
1811 /// <summary>
1912 /// The console application.
@@ -56,7 +49,7 @@ public static DotNetConsoleBuilder CreateDefaultBuilder(string[] args)
5649 // Get the entry assembly of the console application. It will later be scanned to find commands and verbs and their options.
5750 var assembly = Assembly . GetEntryAssembly ( ) ?? throw new DotNetConsoleException ( "Could not determine entry assembly" ) ;
5851
59- return CreateBuilderInternal ( assembly , null , args ) ;
52+ return DotNetConsoleBuilder . CreateBuilderInternal ( assembly , null , args ) ;
6053 }
6154
6255 /// <summary>
@@ -70,7 +63,7 @@ public static DotNetConsoleBuilder CreateBuilderWithReference(Assembly assembly,
7063 {
7164 ArgumentNullException . ThrowIfNull ( assembly ) ;
7265
73- return CreateBuilderInternal ( assembly , null , args ) ;
66+ return DotNetConsoleBuilder . CreateBuilderInternal ( assembly , null , args ) ;
7467 }
7568
7669 /// <summary>
@@ -85,7 +78,7 @@ public static DotNetConsoleBuilder CreateBuilderWithReference(Assembly servicesA
8578 {
8679 ArgumentNullException . ThrowIfNull ( servicesAssembly ) ;
8780
88- return CreateBuilderInternal ( servicesAssembly , verbTypes , args ) ;
81+ return DotNetConsoleBuilder . CreateBuilderInternal ( servicesAssembly , verbTypes , args ) ;
8982 }
9083
9184 /// <summary>
@@ -97,166 +90,6 @@ public async Task RunAsync()
9790 await this . commandLineParserResult . WithParsedAsync ( this . RunWithOptionsAsync ) ;
9891 }
9992
100- /// <summary>
101- /// Creates the default builder.
102- /// </summary>
103- /// <param name="assembly">The assembly.</param>
104- /// <param name="verbTypes">The verb types.</param>
105- /// <param name="args">The arguments.</param>
106- /// <returns>
107- /// The <see cref="DotNetConsoleBuilder" />.
108- /// </returns>
109- private static DotNetConsoleBuilder CreateBuilderInternal ( Assembly assembly , Type [ ] ? verbTypes , string [ ] args )
110- {
111- // Create a HostBuilder
112- var hostBuilder = Host . CreateDefaultBuilder ( args )
113- . ConfigureLogging ( ( context , logging ) =>
114- {
115- AdjustDefaultBuilderLoggingProviders ( logging ) ;
116- logging . AddNLog ( context . Configuration ) ;
117- } )
118- . ConfigureServices ( ( _ , services ) =>
119- {
120- // Register all commands found in the entry assembly.
121- services . Scan ( selector => selector . FromAssemblies ( assembly )
122- . AddClasses ( classes => classes . AssignableTo ( typeof ( IDotNetConsoleCommand < > ) ) )
123- . AsImplementedInterfaces ( ) ) ;
124- } ) ;
125-
126- // Manually build configuration and environment again, because we unfortunately can't access them from the host builder we just created, but want to provide them in the ConsoleApplicationBuilder.
127- var environment = CreateConsoleEnvironment ( args ) ;
128- var configuration = ApplyDefaultConfiguration ( assembly , args , environment ) ;
129-
130- // If verb types were not specified, compile all available verbs for this run by looking for classes with the Verb attribute in the specified assembly
131- verbTypes ??= assembly . GetTypes ( )
132- . Where ( t => t . GetCustomAttribute < VerbAttribute > ( ) != null )
133- . ToArray ( ) ;
134-
135- EnforceStrictVerbMatching ( args , verbTypes ) ;
136- var parsedArguments = Parser . Default . ParseArguments ( args , verbTypes ) ;
137-
138- return new DotNetConsoleBuilder ( hostBuilder , parsedArguments , environment , configuration ) ;
139- }
140-
141- /// <summary>
142- /// Enforce strict verb matching if one verb is marked as default. Otherwise, the default verb will be executed even if that was not the users intention.
143- /// </summary>
144- /// <param name="args">The arguments.</param>
145- /// <param name="availableVerbTypes">The available verb types.</param>
146- /// <exception cref="Neolution.DotNet.Console.DotNetConsoleException">Cannot create builder, because the specified verb '{firstVerb}' matches no command.</exception>
147- private static void EnforceStrictVerbMatching ( string [ ] args , Type [ ] availableVerbTypes )
148- {
149- var availableVerbs = availableVerbTypes . Select ( t => t . GetCustomAttribute < VerbAttribute > ( ) ! ) . ToList ( ) ;
150- if ( ! availableVerbs . Any ( v => v . IsDefault ) )
151- {
152- // If no default verb is defined, we do not enforce strict verb matching
153- return ;
154- }
155-
156- var firstVerb = args . FirstOrDefault ( ) ;
157- if ( string . IsNullOrWhiteSpace ( firstVerb ) || firstVerb . StartsWith ( '-' ) )
158- {
159- // If the user passed no verb, but a default verb is defined, the default verb will be executed
160- return ;
161- }
162-
163- // Names reserved by CommandLineParser library
164- var validFirstArguments = new List < string > { "--help" , "--version" , "help" , "version" } ;
165-
166- // Names of all available verbs
167- validFirstArguments . AddRange ( availableVerbs . Select ( t => t . Name ) ) ;
168-
169- // Check if the first argument can be found in the list of valid arguments
170- var verbMatched = validFirstArguments . Any ( v => v . Equals ( firstVerb , StringComparison . OrdinalIgnoreCase ) ) ;
171- if ( ! verbMatched )
172- {
173- throw new DotNetConsoleException ( $ "Cannot create builder, because the specified verb '{ firstVerb } ' matches no command.") ;
174- }
175- }
176-
177- /// <summary>
178- /// Creates the console environment.
179- /// </summary>
180- /// <param name="args">The command line arguments.</param>
181- /// <returns>The <see cref="IHostEnvironment"/>.</returns>
182- private static DotNetConsoleEnvironment CreateConsoleEnvironment ( string [ ] args )
183- {
184- var configuration = new ConfigurationBuilder ( )
185- . AddEnvironmentVariables ( prefix : "DOTNET_" )
186- . AddCommandLine ( args )
187- . Build ( ) ;
188-
189- return new DotNetConsoleEnvironment
190- {
191- EnvironmentName = configuration [ HostDefaults . EnvironmentKey ] ?? "Production" ,
192- ApplicationName = AppDomain . CurrentDomain . FriendlyName ,
193- ContentRootPath = AppContext . BaseDirectory ,
194- ContentRootFileProvider = new PhysicalFileProvider ( AppContext . BaseDirectory ) ,
195- } ;
196- }
197-
198- /// <summary>
199- /// Applies the default configuration to the console application.
200- /// </summary>
201- /// <param name="assembly">The assembly.</param>
202- /// <param name="args">The arguments.</param>
203- /// <param name="environment">The environment.</param>
204- /// <returns>The <see cref="IConfiguration" />.</returns>
205- private static IConfiguration ApplyDefaultConfiguration ( Assembly assembly , string [ ] args , IHostEnvironment environment )
206- {
207- var configurationBuilder = new ConfigurationBuilder ( )
208- . SetBasePath ( AppContext . BaseDirectory )
209- . AddEnvironmentVariables ( prefix : "DOTNET_" ) ;
210-
211- AddCommandLineConfig ( configurationBuilder , args ) ;
212-
213- configurationBuilder
214- . AddJsonFile ( "appsettings.json" , optional : true , reloadOnChange : true )
215- . AddJsonFile ( $ "appsettings.{ environment . EnvironmentName } .json", optional : true , reloadOnChange : true ) ;
216-
217- if ( environment . IsDevelopment ( ) )
218- {
219- configurationBuilder . AddUserSecrets ( assembly , optional : true , reloadOnChange : true ) ;
220- }
221-
222- configurationBuilder . AddEnvironmentVariables ( ) ;
223-
224- return configurationBuilder . Build ( ) ;
225- }
226-
227- /// <summary>
228- /// Adjusts the default builder logging providers.
229- /// </summary>
230- /// <param name="logging">The logging.</param>
231- private static void AdjustDefaultBuilderLoggingProviders ( ILoggingBuilder logging )
232- {
233- // Remove the default logging providers
234- logging . ClearProviders ( ) ;
235-
236- // Re-add other logging providers that are assigned in Host.CreateDefaultBuilder
237- logging . AddDebug ( ) ;
238- logging . AddEventSourceLogger ( ) ;
239-
240- if ( OperatingSystem . IsWindows ( ) )
241- {
242- // Add the EventLogLoggerProvider on windows machines
243- logging . AddEventLog ( ) ;
244- }
245- }
246-
247- /// <summary>
248- /// Adds the command line configuration.
249- /// </summary>
250- /// <param name="configBuilder">The configuration builder.</param>
251- /// <param name="args">The arguments.</param>
252- private static void AddCommandLineConfig ( IConfigurationBuilder configBuilder , string [ ] ? args )
253- {
254- if ( args is { Length : > 0 } )
255- {
256- configBuilder . AddCommandLine ( args ) ;
257- }
258- }
259-
26093 /// <summary>
26194 /// Runs the command with options asynchronously.
26295 /// </summary>
0 commit comments