Skip to content

Commit 44d3953

Browse files
fmeumcopybara-github
authored andcommitted
Let common ignore unsupported options
Fixes #3054 RELNOTES: Options specified on the pseudo-command `common` in `.rc` files are now ignored by commands that do not support them as long as they are valid options for *any* Bazel command. Previously, commands that did not support all options given for `common` would fail to run. These previous semantics of `common` are now available via the new `always` pseudo-command. Closes #18130. PiperOrigin-RevId: 534940403 Change-Id: I2ae268ae84de3f2b07ff3d1e36bf382bce714968
1 parent bf320d2 commit 44d3953

File tree

14 files changed

+787
-196
lines changed

14 files changed

+787
-196
lines changed

site/en/run/bazelrc.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,14 @@ line specifies when these defaults are applied:
105105
106106
- `startup`: startup options, which go before the command, and are described
107107
in `bazel help startup_options`.
108-
- `common`: options that apply to all Bazel commands.
108+
- `common`: options that should be applied to all Bazel commands that support
109+
them. If a command does not support an option specified in this way, the
110+
option is ignored so long as it is valid for *some* other Bazel command.
111+
Note that this only applies to option names: If the current command accepts
112+
an option with the specified name, but doesn't support the specified value,
113+
it will fail.
114+
- `always`: options that apply to all Bazel commands. If a command does not
115+
support an option specified in this way, it will fail.
109116
- _`command`_: Bazel command, such as `build` or `query` to which the options
110117
apply. These options also apply to all commands that inherit from the
111118
specified command. (For example, `test` inherits from `build`.)

src/main/java/com/google/devtools/build/lib/runtime/BlazeOptionHandler.java

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// limitations under the License.
1414
package com.google.devtools.build.lib.runtime;
1515

16+
import static com.google.common.collect.ImmutableList.toImmutableList;
17+
1618
import com.google.common.annotations.VisibleForTesting;
1719
import com.google.common.base.Joiner;
1820
import com.google.common.collect.ArrayListMultimap;
@@ -42,6 +44,7 @@
4244
import com.google.devtools.common.options.InvocationPolicyEnforcer;
4345
import com.google.devtools.common.options.OptionDefinition;
4446
import com.google.devtools.common.options.OptionPriority.PriorityCategory;
47+
import com.google.devtools.common.options.OptionsBase;
4548
import com.google.devtools.common.options.OptionsParser;
4649
import com.google.devtools.common.options.OptionsParsingException;
4750
import com.google.devtools.common.options.OptionsParsingResult;
@@ -74,6 +77,14 @@ public final class BlazeOptionHandler {
7477
"client_env",
7578
"client_cwd");
7679

80+
// All options set on this pseudo command are inherited by all commands, with unrecognized options
81+
// resulting in an error.
82+
private static final String ALWAYS_PSEUDO_COMMAND = "always";
83+
84+
// All options set on this pseudo command are inherited by all commands, with unrecognized options
85+
// being ignored as long as they are recognized by at least one (other) command.
86+
private static final String COMMON_PSEUDO_COMMAND = "common";
87+
7788
// Marks an event to indicate a parsing error.
7889
static final String BAD_OPTION_TAG = "invalidOption";
7990
// Separates the invalid tag from the full error message for easier parsing.
@@ -86,6 +97,7 @@ public final class BlazeOptionHandler {
8697
private final Command commandAnnotation;
8798
private final InvocationPolicy invocationPolicy;
8899
private final List<String> rcfileNotes = new ArrayList<>();
100+
private final ImmutableList<Class<? extends OptionsBase>> allOptionsClasses;
89101

90102
BlazeOptionHandler(
91103
BlazeRuntime runtime,
@@ -100,6 +112,16 @@ public final class BlazeOptionHandler {
100112
this.commandAnnotation = commandAnnotation;
101113
this.optionsParser = optionsParser;
102114
this.invocationPolicy = invocationPolicy;
115+
this.allOptionsClasses =
116+
runtime.getCommandMap().values().stream()
117+
.map(BlazeCommand::getClass)
118+
.flatMap(
119+
cmd ->
120+
BlazeCommandUtils.getOptions(
121+
cmd, runtime.getBlazeModules(), runtime.getRuleClassProvider())
122+
.stream())
123+
.distinct()
124+
.collect(toImmutableList());
103125
}
104126

105127
/**
@@ -199,7 +221,36 @@ void parseRcOptions(
199221
"%s:\n %s'%s' options: %s",
200222
source, inherited, commandToParse, Joiner.on(' ').join(rcArgs.getArgs())));
201223
}
202-
optionsParser.parse(PriorityCategory.RC_FILE, rcArgs.getRcFile(), rcArgs.getArgs());
224+
if (commandToParse.equals(COMMON_PSEUDO_COMMAND)) {
225+
// Pass in options data for all commands supported by the runtime so that options that
226+
// apply to some but not the current command can be ignored.
227+
//
228+
// Important note: The consistency checks performed by
229+
// OptionsParser#getFallbackOptionsData ensure that there aren't any two options across
230+
// all commands that have the same name but parse differently (e.g. because one accepts
231+
// a value and the other doesn't). This means that the options available on a command
232+
// limit the options available on other commands even without command inheritance. This
233+
// restriction is necessary to ensure that the options specified on the "common"
234+
// pseudo command can be parsed unambiguously.
235+
ImmutableList<String> ignoredArgs =
236+
optionsParser.parseWithSourceFunction(
237+
PriorityCategory.RC_FILE,
238+
o -> rcArgs.getRcFile(),
239+
rcArgs.getArgs(),
240+
OptionsParser.getFallbackOptionsData(allOptionsClasses));
241+
if (!ignoredArgs.isEmpty()) {
242+
// Append richer information to the note.
243+
int index = rcfileNotes.size() - 1;
244+
String note = rcfileNotes.get(index);
245+
note +=
246+
String.format(
247+
"\n Ignored as unsupported by '%s': %s",
248+
commandAnnotation.name(), Joiner.on(' ').join(ignoredArgs));
249+
rcfileNotes.set(index, note);
250+
}
251+
} else {
252+
optionsParser.parse(PriorityCategory.RC_FILE, rcArgs.getRcFile(), rcArgs.getArgs());
253+
}
203254
}
204255
}
205256
}
@@ -235,7 +286,8 @@ private void parseArgsAndConfigs(List<String> args, ExtendedEventHandler eventHa
235286
optionsParser.parseWithSourceFunction(
236287
PriorityCategory.COMMAND_LINE,
237288
commandOptionSourceFunction,
238-
defaultOverridesAndRcSources.build());
289+
defaultOverridesAndRcSources.build(),
290+
/* fallbackData= */ null);
239291

240292
// Command-specific options from .blazerc passed in via --default_override and --rc_source.
241293
ClientOptions rcFileOptions = optionsParser.getOptions(ClientOptions.class);
@@ -249,7 +301,10 @@ private void parseArgsAndConfigs(List<String> args, ExtendedEventHandler eventHa
249301

250302
// Parses the remaining command-line options.
251303
optionsParser.parseWithSourceFunction(
252-
PriorityCategory.COMMAND_LINE, commandOptionSourceFunction, remainingCmdLine.build());
304+
PriorityCategory.COMMAND_LINE,
305+
commandOptionSourceFunction,
306+
remainingCmdLine.build(),
307+
/* fallbackData= */ null);
253308

254309
if (commandAnnotation.builds()) {
255310
// splits project files from targets in the traditional sense
@@ -459,14 +514,17 @@ void expandConfigOptions(
459514
ConfigExpander.expandConfigOptions(
460515
eventHandler,
461516
commandToRcArgs,
517+
commandAnnotation.name(),
462518
getCommandNamesToParse(commandAnnotation),
463519
rcfileNotes::add,
464-
optionsParser);
520+
optionsParser,
521+
OptionsParser.getFallbackOptionsData(allOptionsClasses));
465522
}
466523

467524
private static List<String> getCommandNamesToParse(Command commandAnnotation) {
468525
List<String> result = new ArrayList<>();
469-
result.add("common");
526+
result.add(ALWAYS_PSEUDO_COMMAND);
527+
result.add(COMMON_PSEUDO_COMMAND);
470528
getCommandNamesToParseHelper(commandAnnotation, result);
471529
return result;
472530
}
@@ -557,7 +615,9 @@ static ListMultimap<String, RcChunkOfArgs> structureRcOptionsAndConfigs(
557615
if (index > 0) {
558616
command = command.substring(0, index);
559617
}
560-
if (!validCommands.contains(command) && !command.equals("common")) {
618+
if (!validCommands.contains(command)
619+
&& !command.equals(ALWAYS_PSEUDO_COMMAND)
620+
&& !command.equals(COMMON_PSEUDO_COMMAND)) {
561621
eventHandler.handle(
562622
Event.warn(
563623
"while reading option defaults file '"

src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,8 @@ private static OptionsParsingResult parseStartupOptions(
11121112

11131113
// Then parse the command line again, this time with the correct option sources
11141114
parser = OptionsParser.builder().optionsClasses(optionClasses).allowResidue(false).build();
1115-
parser.parseWithSourceFunction(PriorityCategory.COMMAND_LINE, sourceFunction, args);
1115+
parser.parseWithSourceFunction(
1116+
PriorityCategory.COMMAND_LINE, sourceFunction, args, /* fallbackData= */ null);
11161117
return parser;
11171118
}
11181119

src/main/java/com/google/devtools/build/lib/runtime/ConfigExpander.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
// limitations under the License.
1414
package com.google.devtools.build.lib.runtime;
1515

16+
import com.google.common.base.Joiner;
1617
import com.google.common.collect.ImmutableList;
1718
import com.google.common.collect.Iterables;
1819
import com.google.common.collect.ListMultimap;
1920
import com.google.devtools.build.lib.events.Event;
2021
import com.google.devtools.build.lib.events.EventHandler;
2122
import com.google.devtools.build.lib.util.OS;
23+
import com.google.devtools.common.options.OpaqueOptionsData;
2224
import com.google.devtools.common.options.OptionValueDescription;
2325
import com.google.devtools.common.options.OptionsParser;
2426
import com.google.devtools.common.options.OptionsParsingException;
@@ -29,6 +31,7 @@
2931
import java.util.List;
3032
import java.util.Set;
3133
import java.util.function.Consumer;
34+
import javax.annotation.Nullable;
3235

3336
/** Encapsulates logic for performing --config option expansion. */
3437
final class ConfigExpander {
@@ -86,9 +89,11 @@ private static boolean shouldEnablePlatformSpecificConfig(
8689
static void expandConfigOptions(
8790
EventHandler eventHandler,
8891
ListMultimap<String, RcChunkOfArgs> commandToRcArgs,
92+
String currentCommand,
8993
List<String> commandsToParse,
9094
Consumer<String> rcFileNotesConsumer,
91-
OptionsParser optionsParser)
95+
OptionsParser optionsParser,
96+
@Nullable OpaqueOptionsData fallbackData)
9297
throws OptionsParsingException {
9398

9499
OptionValueDescription configValueDescription =
@@ -110,10 +115,18 @@ static void expandConfigOptions(
110115
commandsToParse,
111116
configValueToExpand,
112117
rcFileNotesConsumer);
113-
optionsParser.parseArgsAsExpansionOfOption(
114-
configInstance,
115-
String.format("expanded from --config=%s", configValueToExpand),
116-
expansion);
118+
var ignoredArgs =
119+
optionsParser.parseArgsAsExpansionOfOption(
120+
configInstance,
121+
String.format("expanded from --config=%s", configValueToExpand),
122+
expansion,
123+
fallbackData);
124+
if (!ignoredArgs.isEmpty()) {
125+
rcFileNotesConsumer.accept(
126+
String.format(
127+
"Ignored as unsupported by '%s': %s",
128+
currentCommand, Joiner.on(' ').join(ignoredArgs)));
129+
}
117130
}
118131
}
119132

@@ -131,7 +144,8 @@ static void expandConfigOptions(
131144
optionsParser.parseArgsAsExpansionOfOption(
132145
Iterables.getOnlyElement(enablePlatformSpecificConfigDescription.getCanonicalInstances()),
133146
String.format("enabled by --enable_platform_specific_config"),
134-
expansion);
147+
expansion,
148+
fallbackData);
135149
}
136150

137151
// At this point, we've expanded everything, identify duplicates, if any, to warn about

src/main/java/com/google/devtools/common/options/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ java_library(
4949
],
5050
),
5151
deps = [
52+
"//src/main/java/com/google/devtools/build/lib/util:pair",
5253
"//third_party:auto_value",
5354
"//third_party:caffeine",
5455
"//third_party:guava",

0 commit comments

Comments
 (0)