20
20
import com .google .common .base .Preconditions ;
21
21
import com .google .common .collect .ArrayListMultimap ;
22
22
import com .google .common .collect .ImmutableList ;
23
+ import com .google .common .collect .ImmutableListMultimap ;
23
24
import com .google .common .collect .ImmutableSet ;
24
25
import com .google .common .collect .Iterables ;
25
26
import com .google .common .collect .ListMultimap ;
29
30
import com .google .devtools .build .lib .events .EventHandler ;
30
31
import com .google .devtools .build .lib .events .ExtendedEventHandler ;
31
32
import com .google .devtools .build .lib .packages .Target ;
33
+ import com .google .devtools .build .lib .runtime .ConfigFlagDefinitions .ConfigDefinition ;
32
34
import com .google .devtools .build .lib .runtime .StarlarkOptionsParser .BuildSettingLoader ;
33
35
import com .google .devtools .build .lib .runtime .proto .InvocationPolicyOuterClass .InvocationPolicy ;
34
36
import com .google .devtools .build .lib .server .FailureDetails ;
@@ -245,7 +247,13 @@ void parseRcOptions(
245
247
}
246
248
}
247
249
248
- private void parseArgsAndConfigs (List <String > args , ExtendedEventHandler eventHandler )
250
+ /**
251
+ * Returns a map from rc file definitions to the options they define and which rc files defined.
252
+ * them. For example, "build:asan" keys a {@code --config=asan} definition and "build" keys
253
+ * options that apply to all build commands.
254
+ */
255
+ private ListMultimap <String , RcChunkOfArgs > parseArgsAndConfigs (
256
+ List <String > args , ExtendedEventHandler eventHandler )
249
257
throws OptionsParsingException , InterruptedException , AbruptExitException {
250
258
Path workspaceDirectory = workspace .getWorkspace ();
251
259
// TODO(ulfjack): The working directory is passed by the client as part of CommonCommandOptions,
@@ -308,6 +316,7 @@ private void parseArgsAndConfigs(List<String> args, ExtendedEventHandler eventHa
308
316
}
309
317
310
318
expandConfigOptions (eventHandler , commandToRcArgs );
319
+ return commandToRcArgs ;
311
320
}
312
321
313
322
/**
@@ -423,6 +432,10 @@ DetailedExitCode parseStarlarkOptions(CommandEnvironment env) {
423
432
return DetailedExitCode .success ();
424
433
}
425
434
435
+ /** Detailed parsing results: exit code and {@code --config=foo} definitions. */
436
+ static record DetailedParseResults (
437
+ DetailedExitCode detailedExitCode , ConfigFlagDefinitions configFlagDefinitions ) {}
438
+
426
439
/**
427
440
* Parses the options, taking care not to generate any output to outErr, return, or throw an
428
441
* exception.
@@ -433,29 +446,51 @@ DetailedExitCode parseOptions(
433
446
List <String > args ,
434
447
ExtendedEventHandler eventHandler ,
435
448
ImmutableList .Builder <OptionAndRawValue > invocationPolicyFlagListBuilder ) {
436
- DetailedExitCode result =
437
- parseOptionsInternal (args , eventHandler , invocationPolicyFlagListBuilder );
438
- if (!result .isSuccess ()) {
449
+ DetailedParseResults result =
450
+ parseOptionsInternal (
451
+ args , eventHandler , invocationPolicyFlagListBuilder , /* getConfigDefinitions= */ false );
452
+ if (!result .detailedExitCode .isSuccess ()) {
439
453
optionsParser .setError ();
440
454
}
441
- return result ;
455
+ return result . detailedExitCode ;
442
456
}
443
457
444
- private DetailedExitCode parseOptionsInternal (
458
+ /**
459
+ * {@link #parseOptions} variation that also returns {@code --config=foo} definitions. Callers can
460
+ * use this to determine which flags {@code --config=foo} sets.
461
+ */
462
+ DetailedParseResults parseOptionsAndGetConfigDefinitions (
445
463
List <String > args ,
446
464
ExtendedEventHandler eventHandler ,
447
465
ImmutableList .Builder <OptionAndRawValue > invocationPolicyFlagListBuilder ) {
466
+ DetailedParseResults result =
467
+ parseOptionsInternal (
468
+ args , eventHandler , invocationPolicyFlagListBuilder , /* getConfigDefinitions= */ true );
469
+ if (!result .detailedExitCode .isSuccess ()) {
470
+ optionsParser .setError ();
471
+ }
472
+ return result ;
473
+ }
474
+
475
+ private DetailedParseResults parseOptionsInternal (
476
+ List <String > args ,
477
+ ExtendedEventHandler eventHandler ,
478
+ ImmutableList .Builder <OptionAndRawValue > invocationPolicyFlagListBuilder ,
479
+ boolean getConfigDefinitions ) {
448
480
// The initialization code here was carefully written to parse the options early before we call
449
481
// into the BlazeModule APIs, which means we must not generate any output to outErr, return, or
450
482
// throw an exception. All the events happening here are instead stored in a temporary event
451
483
// handler, and later replayed.
452
484
DetailedExitCode earlyExitCode = checkCwdInWorkspace (eventHandler );
453
485
if (!earlyExitCode .isSuccess ()) {
454
- return earlyExitCode ;
486
+ return new DetailedParseResults (
487
+ earlyExitCode , new ConfigFlagDefinitions (ImmutableListMultimap .of ()));
455
488
}
456
489
490
+ ListMultimap <String , RcChunkOfArgs > rcDefinitions = ImmutableListMultimap .of ();
491
+ DetailedExitCode exitCode ;
457
492
try {
458
- parseArgsAndConfigs (args , eventHandler );
493
+ rcDefinitions = parseArgsAndConfigs (args , eventHandler );
459
494
// Allow the command to edit the options.
460
495
command .editOptions (optionsParser );
461
496
// Merge the invocation policy that is user-supplied, from the command line, and any
@@ -485,22 +520,49 @@ private DetailedExitCode parseOptionsInternal(
485
520
for (String warning : commonOptions .deprecationWarnings ) {
486
521
eventHandler .handle (Event .warn (warning ));
487
522
}
523
+ exitCode = DetailedExitCode .success ();
488
524
} catch (OptionsParsingException e ) {
489
525
String logMessage = "Error parsing options" ;
490
526
logger .atInfo ().withCause (e ).log ("%s" , logMessage );
491
- return processOptionsParsingException (
492
- eventHandler , e , logMessage , Code .OPTIONS_PARSE_FAILURE );
527
+ exitCode =
528
+ processOptionsParsingException ( eventHandler , e , logMessage , Code .OPTIONS_PARSE_FAILURE );
493
529
} catch (InterruptedException e ) {
494
- return DetailedExitCode .of (
495
- FailureDetail .newBuilder ()
496
- .setInterrupted (
497
- FailureDetails .Interrupted .newBuilder ()
498
- .setCode (FailureDetails .Interrupted .Code .INTERRUPTED ))
499
- .build ());
530
+ exitCode =
531
+ DetailedExitCode .of (
532
+ FailureDetail .newBuilder ()
533
+ .setInterrupted (
534
+ FailureDetails .Interrupted .newBuilder ()
535
+ .setCode (FailureDetails .Interrupted .Code .INTERRUPTED ))
536
+ .build ());
500
537
} catch (AbruptExitException e ) {
501
- return e .getDetailedExitCode ();
538
+ exitCode = e .getDetailedExitCode ();
502
539
}
503
- return DetailedExitCode .success ();
540
+
541
+ if (!getConfigDefinitions ) {
542
+ return new DetailedParseResults (
543
+ exitCode , new ConfigFlagDefinitions (ImmutableListMultimap .of ()));
544
+ }
545
+ // Transforms all rc definitions into valid --config definitions for this command. For example,
546
+ // "build:asan" is valid for a build command but not "test:asan". Rc definitions like "build"
547
+ // aren't included because those aren't --config definitions.
548
+ var validConfigDefs = new ImmutableListMultimap .Builder <String , ConfigDefinition >();
549
+ List <String > matchingRcCommands = getCommandNamesToParse (commandAnnotation );
550
+ for (var entry : rcDefinitions .entries ()) {
551
+ String rcKey = entry .getKey ();
552
+ int firstColon = rcKey .indexOf (":" );
553
+ if (firstColon == -1 ) {
554
+ continue ;
555
+ }
556
+ String cmd = rcKey .substring (0 , firstColon );
557
+ String configName = rcKey .substring (firstColon + 1 );
558
+ if (matchingRcCommands .contains (cmd )) {
559
+ validConfigDefs .put (
560
+ configName ,
561
+ new ConfigFlagDefinitions .ConfigDefinition (
562
+ ImmutableList .copyOf (entry .getValue ().getArgs ()), entry .getValue ().getRcFile ()));
563
+ }
564
+ }
565
+ return new DetailedParseResults (exitCode , new ConfigFlagDefinitions (validConfigDefs .build ()));
504
566
}
505
567
506
568
/**
0 commit comments