7
7
using System . CommandLine . Parsing ;
8
8
using System . Diagnostics ;
9
9
using Microsoft . DotNet . Cli . CommandFactory ;
10
+ using Microsoft . DotNet . Cli . CommandFactory . CommandResolution ;
10
11
using Microsoft . DotNet . Cli . Commands . Run ;
11
12
using Microsoft . DotNet . Cli . Commands . Workload ;
12
13
using Microsoft . DotNet . Cli . Extensions ;
@@ -129,22 +130,6 @@ internal static int ProcessArgs(string[] args, TimeSpan startupTime)
129
130
using ( new PerformanceMeasurement ( performanceData , "Parse Time" ) )
130
131
{
131
132
parseResult = Parser . Instance . Parse ( args ) ;
132
- // If we didn't match any built-in commands, and a C# file path is the first argument,
133
- // parse as `dotnet run file.cs ..rest_of_args` instead.
134
- if ( parseResult . CommandResult . Command is RootCommand
135
- && parseResult . GetValue ( Parser . DotnetSubCommand ) is { } unmatchedCommandOrFile
136
- && VirtualProjectBuildingCommand . IsValidEntryPointPath ( unmatchedCommandOrFile ) )
137
- {
138
- List < string > otherTokens = new ( parseResult . Tokens . Count - 1 ) ;
139
- foreach ( var token in parseResult . Tokens )
140
- {
141
- if ( token . Type != TokenType . Argument || token . Value != unmatchedCommandOrFile )
142
- {
143
- otherTokens . Add ( token . Value ) ;
144
- }
145
- }
146
- parseResult = Parser . Instance . Parse ( [ "run" , unmatchedCommandOrFile , .. otherTokens ] ) ;
147
- }
148
133
149
134
// Avoid create temp directory with root permission and later prevent access in non sudo
150
135
// This method need to be run very early before temp folder get created
@@ -251,36 +236,35 @@ internal static int ProcessArgs(string[] args, TimeSpan startupTime)
251
236
int exitCode ;
252
237
if ( parseResult . CanBeInvoked ( ) )
253
238
{
254
- PerformanceLogEventSource . Log . BuiltInCommandStart ( ) ;
255
-
256
- try
257
- {
258
- exitCode = parseResult . Invoke ( ) ;
259
- exitCode = AdjustExitCode ( parseResult , exitCode ) ;
260
- }
261
- catch ( Exception exception )
262
- {
263
- exitCode = Parser . ExceptionHandler ( exception , parseResult ) ;
264
- }
265
-
266
- PerformanceLogEventSource . Log . BuiltInCommandStop ( ) ;
239
+ InvokeBuiltInCommand ( parseResult , out exitCode ) ;
267
240
}
268
241
else
269
242
{
270
243
PerformanceLogEventSource . Log . ExtensibleCommandResolverStart ( ) ;
271
244
try
272
245
{
273
- var resolvedCommand = CommandFactoryUsingResolver . Create (
274
- "dotnet-" + parseResult . GetValue ( Parser . DotnetSubCommand ) ,
275
- args . GetSubArguments ( ) ,
276
- FrameworkConstants . CommonFrameworks . NetStandardApp15 ) ;
277
- PerformanceLogEventSource . Log . ExtensibleCommandResolverStop ( ) ;
246
+ string commandName = "dotnet-" + parseResult . GetValue ( Parser . DotnetSubCommand ) ;
247
+ var resolvedCommandSpec = CommandResolver . TryResolveCommandSpec (
248
+ new DefaultCommandResolverPolicy ( ) ,
249
+ commandName ,
250
+ args . GetSubArguments ( ) ,
251
+ FrameworkConstants . CommonFrameworks . NetStandardApp15 ) ;
252
+
253
+ if ( resolvedCommandSpec is null && TryRunFileBasedApp ( parseResult ) is { } fileBasedAppExitCode )
254
+ {
255
+ exitCode = fileBasedAppExitCode ;
256
+ }
257
+ else
258
+ {
259
+ var resolvedCommand = CommandFactoryUsingResolver . CreateOrThrow ( commandName , resolvedCommandSpec ) ;
260
+ PerformanceLogEventSource . Log . ExtensibleCommandResolverStop ( ) ;
278
261
279
- PerformanceLogEventSource . Log . ExtensibleCommandStart ( ) ;
280
- var result = resolvedCommand . Execute ( ) ;
281
- PerformanceLogEventSource . Log . ExtensibleCommandStop ( ) ;
262
+ PerformanceLogEventSource . Log . ExtensibleCommandStart ( ) ;
263
+ var result = resolvedCommand . Execute ( ) ;
264
+ PerformanceLogEventSource . Log . ExtensibleCommandStop ( ) ;
282
265
283
- exitCode = result . ExitCode ;
266
+ exitCode = result . ExitCode ;
267
+ }
284
268
}
285
269
catch ( CommandUnknownException e )
286
270
{
@@ -297,6 +281,50 @@ internal static int ProcessArgs(string[] args, TimeSpan startupTime)
297
281
TelemetryClient . Dispose ( ) ;
298
282
299
283
return exitCode ;
284
+
285
+ static int ? TryRunFileBasedApp ( ParseResult parseResult )
286
+ {
287
+ // If we didn't match any built-in commands, and a C# file path is the first argument,
288
+ // parse as `dotnet run file.cs ..rest_of_args` instead.
289
+ if ( parseResult . CommandResult . Command is RootCommand
290
+ && parseResult . GetValue ( Parser . DotnetSubCommand ) is { } unmatchedCommandOrFile
291
+ && VirtualProjectBuildingCommand . IsValidEntryPointPath ( unmatchedCommandOrFile ) )
292
+ {
293
+ List < string > otherTokens = new ( parseResult . Tokens . Count - 1 ) ;
294
+ foreach ( var token in parseResult . Tokens )
295
+ {
296
+ if ( token . Type != TokenType . Argument || token . Value != unmatchedCommandOrFile )
297
+ {
298
+ otherTokens . Add ( token . Value ) ;
299
+ }
300
+ }
301
+ parseResult = Parser . Instance . Parse ( [ "run" , unmatchedCommandOrFile , .. otherTokens ] ) ;
302
+
303
+ InvokeBuiltInCommand ( parseResult , out var exitCode ) ;
304
+ return exitCode ;
305
+ }
306
+
307
+ return null ;
308
+ }
309
+
310
+ static void InvokeBuiltInCommand ( ParseResult parseResult , out int exitCode )
311
+ {
312
+ Debug . Assert ( parseResult . CanBeInvoked ( ) ) ;
313
+
314
+ PerformanceLogEventSource . Log . BuiltInCommandStart ( ) ;
315
+
316
+ try
317
+ {
318
+ exitCode = parseResult . Invoke ( ) ;
319
+ exitCode = AdjustExitCode ( parseResult , exitCode ) ;
320
+ }
321
+ catch ( Exception exception )
322
+ {
323
+ exitCode = Parser . ExceptionHandler ( exception , parseResult ) ;
324
+ }
325
+
326
+ PerformanceLogEventSource . Log . BuiltInCommandStop ( ) ;
327
+ }
300
328
}
301
329
302
330
private static int AdjustExitCode ( ParseResult parseResult , int exitCode )
0 commit comments