Allow optional-imports for rc files.
`try-import` will not cause an error if the file does not exist. We warn for imports that lead to duplicate rc files being read, but we can't remove the duplicate without messing up ordering semantics.
Users should be wary if they import the same file from two different rc files, as duplicate options can be surprising in some cases, notably if the options are passed on to another tool which does not accept duplicates. A warning will be printed, but warnings are easy to ignore.
Fixes #5765
RELNOTES: None.
PiperOrigin-RevId: 211869620
diff --git a/src/main/cpp/rc_file.cc b/src/main/cpp/rc_file.cc
index fad487a..e356ca6 100644
--- a/src/main/cpp/rc_file.cc
+++ b/src/main/cpp/rc_file.cc
@@ -30,6 +30,9 @@
using std::string;
using std::vector;
+static constexpr const char* kCommandImport = "import";
+static constexpr const char* kCommandTryImport = "try-import";
+
RcFile::RcFile(string filename, const WorkspaceLayout* workspace_layout,
string workspace)
: filename_(std::move(filename)),
@@ -94,7 +97,7 @@
string command = words[0];
- if (command == "import") {
+ if (command == kCommandImport || command == kCommandTryImport) {
if (words.size() != 2 ||
(words[1].compare(0, workspace_layout_->WorkspacePrefixLength,
workspace_layout_->WorkspacePrefix) == 0 &&
@@ -122,7 +125,19 @@
import_stack->push_back(words[1]);
ParseError parse_error = ParseFile(words[1], import_stack, error_text);
if (parse_error != ParseError::NONE) {
- return parse_error;
+ if (parse_error == ParseError::UNREADABLE_FILE &&
+ command == kCommandTryImport) {
+ // For try-import, we ignore it if we couldn't find a file.
+ BAZEL_LOG(INFO) << "Skipped optional import of " << words[1]
+ << ", the specified rc file either does not exist or "
+ "is not readable.";
+ *error_text = "";
+ } else {
+ // Files that are there but are malformed or introduce a loop are
+ // still a problem, though, so perpetuate those errors as we would
+ // for a normal import statement.
+ return parse_error;
+ }
}
import_stack->pop_back();
} else {
diff --git a/src/test/cpp/rc_file_test.cc b/src/test/cpp/rc_file_test.cc
index be9ac06..816535d 100644
--- a/src/test/cpp/rc_file_test.cc
+++ b/src/test/cpp/rc_file_test.cc
@@ -155,22 +155,6 @@
return false;
}
- void ParseOptionsAndCheckOutput(
- const std::vector<std::string>& args,
- const blaze_exit_code::ExitCode expected_exit_code,
- const std::string& expected_error_regex,
- const std::string& expected_output_regex) {
- std::string error;
- testing::internal::CaptureStderr();
- const blaze_exit_code::ExitCode exit_code =
- option_processor_->ParseOptions(args, workspace_, cwd_, &error);
- const std::string output = testing::internal::GetCapturedStderr();
-
- ASSERT_EQ(expected_exit_code, exit_code) << error;
- ASSERT_THAT(error, ContainsRegex(expected_error_regex));
- ASSERT_THAT(output, ContainsRegex(expected_output_regex));
- }
-
const std::string workspace_;
std::string cwd_;
const std::string binary_dir_;
@@ -370,7 +354,24 @@
EXPECT_EQ(expected_rc_que, parsed_rcs[0].get()->sources());
}
-using ParseOptionsTest = RcFileTest;
+class ParseOptionsTest : public RcFileTest {
+ protected:
+ void ParseOptionsAndCheckOutput(
+ const std::vector<std::string>& args,
+ const blaze_exit_code::ExitCode expected_exit_code,
+ const std::string& expected_error_regex,
+ const std::string& expected_output_regex) {
+ std::string error;
+ testing::internal::CaptureStderr();
+ const blaze_exit_code::ExitCode exit_code =
+ option_processor_->ParseOptions(args, workspace_, cwd_, &error);
+ const std::string output = testing::internal::GetCapturedStderr();
+
+ ASSERT_EQ(expected_exit_code, exit_code) << error;
+ ASSERT_THAT(error, ContainsRegex(expected_error_regex));
+ ASSERT_THAT(output, ContainsRegex(expected_output_regex));
+ }
+};
TEST_F(ParseOptionsTest, IgnoreAllRcFilesIgnoresAllMasterAndUserRcFiles) {
// Put fake options in different expected rc files, to check that none of them
@@ -621,46 +622,167 @@
"--max_idle_secs=123\n"));
}
-TEST_F(ParseOptionsTest, BazelRcImportsMaintainsFlagOrdering) {
- // Override one of the master bazelrc's flags in the custom bazelrc.
- const std::string imported_rc_path =
- blaze_util::JoinPath(workspace_, "myimportedbazelrc");
- ASSERT_TRUE(
- blaze_util::MakeDirectories(blaze_util::Dirname(imported_rc_path), 0755));
- ASSERT_TRUE(blaze_util::WriteFile(
- "startup --max_idle_secs=123\nstartup --io_nice_level=4",
- imported_rc_path, 0755));
+class BlazercImportTest : public ParseOptionsTest {
+ protected:
+ void TestBazelRcImportsMaintainsFlagOrdering(const std::string& import_type) {
+ // Override one of the master bazelrc's flags in the custom bazelrc.
+ const std::string imported_rc_path =
+ blaze_util::JoinPath(workspace_, "myimportedbazelrc");
+ ASSERT_TRUE(blaze_util::MakeDirectories(
+ blaze_util::Dirname(imported_rc_path), 0755));
+ ASSERT_TRUE(blaze_util::WriteFile(
+ "startup --max_idle_secs=123\n"
+ "startup --io_nice_level=4",
+ imported_rc_path, 0755));
- // Add startup flags the imported bazelrc.
- std::string workspace_rc;
- ASSERT_TRUE(SetUpWorkspaceRcFile("startup --max_idle_secs=42\nimport " +
- imported_rc_path +
- "\nstartup --io_nice_level=6",
- &workspace_rc));
+ // Add startup flags the imported bazelrc.
+ std::string workspace_rc;
+ ASSERT_TRUE(SetUpWorkspaceRcFile(
+ "startup --max_idle_secs=42\n" +
+ import_type + " " + imported_rc_path + "\n"
+ "startup --io_nice_level=6",
+ &workspace_rc));
- const std::vector<std::string> args = {"bazel", "build"};
- ParseOptionsAndCheckOutput(args, blaze_exit_code::SUCCESS, "", "");
+ const std::vector<std::string> args = {"bazel", "build"};
+ ParseOptionsAndCheckOutput(args, blaze_exit_code::SUCCESS, "", "");
- EXPECT_EQ(123, option_processor_->GetParsedStartupOptions()->max_idle_secs);
- EXPECT_EQ(6, option_processor_->GetParsedStartupOptions()->io_nice_level);
+ EXPECT_EQ(123, option_processor_->GetParsedStartupOptions()->max_idle_secs);
+ EXPECT_EQ(6, option_processor_->GetParsedStartupOptions()->io_nice_level);
- // Check that the options are reported in the correct order in the provenance
- // message, the imported file between the two master flags
- testing::internal::CaptureStderr();
- option_processor_->PrintStartupOptionsProvenanceMessage();
- const std::string output = testing::internal::GetCapturedStderr();
+ // Check that the options are reported in the correct order in the
+ // provenance message, the imported file between the two master flags
+ testing::internal::CaptureStderr();
+ option_processor_->PrintStartupOptionsProvenanceMessage();
+ const std::string output = testing::internal::GetCapturedStderr();
- EXPECT_THAT(
- output,
- MatchesRegex("INFO: Reading 'startup' options from .*workspace.*bazelrc: "
- "--max_idle_secs=42\n"
- "INFO: Reading 'startup' options from .*myimportedbazelrc: "
- "--max_idle_secs=123 --io_nice_level=4\n"
- "INFO: Reading 'startup' options from .*workspace.*bazelrc: "
- "--io_nice_level=6\n"));
-}
+ EXPECT_THAT(
+ output,
+ MatchesRegex(
+ "INFO: Reading 'startup' options from .*workspace.*bazelrc: "
+ "--max_idle_secs=42\n"
+ "INFO: Reading 'startup' options from .*myimportedbazelrc: "
+ "--max_idle_secs=123 --io_nice_level=4\n"
+ "INFO: Reading 'startup' options from .*workspace.*bazelrc: "
+ "--io_nice_level=6\n"));
+ }
-TEST_F(ParseOptionsTest, BazelRcImportFailsForMissingFile) {
+ void TestThatDoubleImportsCauseAWarning(const std::string& import_type) {
+ const std::string imported_rc_path =
+ blaze_util::JoinPath(workspace_, "myimportedbazelrc");
+ ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
+
+ // Import the custom location twice.
+ std::string workspace_rc;
+ ASSERT_TRUE(SetUpWorkspaceRcFile(
+ import_type + " " + imported_rc_path + "\n" +
+ import_type + " " + imported_rc_path + "\n",
+ &workspace_rc));
+
+ const std::vector<std::string> args = {"bazel", "build"};
+ ParseOptionsAndCheckOutput(
+ args, blaze_exit_code::SUCCESS, "",
+ "WARNING: Duplicate rc file: .*myimportedbazelrc is imported multiple "
+ "times from .*workspace.*bazelrc\n");
+ }
+
+ void TestThatDoubleImportWithWorkspaceRelativeSyntaxCauseAWarning(
+ const std::string& import_type) {
+ const std::string imported_rc_path =
+ blaze_util::JoinPath(workspace_, "myimportedbazelrc");
+ ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
+
+ // Import the custom location twice.
+ std::string workspace_rc;
+ ASSERT_TRUE(
+ SetUpWorkspaceRcFile(
+ import_type + " " + imported_rc_path + "\n" +
+ import_type + " %workspace%/myimportedbazelrc\n",
+ &workspace_rc));
+
+ const std::vector<std::string> args = {"bazel", "build"};
+ ParseOptionsAndCheckOutput(
+ args, blaze_exit_code::SUCCESS, "",
+ "WARNING: Duplicate rc file: .*myimportedbazelrc is imported multiple "
+ "times from .*workspace.*bazelrc\n");
+ }
+
+ void TestThatDoubleImportWithExcessPathSyntaxCauseAWarning(
+ const std::string& import_type) {
+ const std::string imported_rc_path =
+ blaze_util::JoinPath(workspace_, "myimportedbazelrc");
+ ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
+
+ // Import the custom location twice.
+ std::string workspace_rc;
+ ASSERT_TRUE(
+ SetUpWorkspaceRcFile(
+ import_type + " " + imported_rc_path + "\n" +
+ import_type + " %workspace%///.//myimportedbazelrc\n",
+ &workspace_rc));
+
+ const std::vector<std::string> args = {"bazel", "build"};
+ ParseOptionsAndCheckOutput(
+ args, blaze_exit_code::SUCCESS, "",
+ "WARNING: Duplicate rc file: .*myimportedbazelrc is imported multiple "
+ "times from .*workspace.*bazelrc\n");
+ }
+
+ void TestThatDeepDoubleImportCausesAWarning(const std::string& import_type) {
+ const std::string dual_imported_rc_path =
+ blaze_util::JoinPath(workspace_, "dual_imported.bazelrc");
+ ASSERT_TRUE(blaze_util::WriteFile("", dual_imported_rc_path, 0755));
+
+ const std::string intermediate_import_1 =
+ blaze_util::JoinPath(workspace_, "intermediate_import_1");
+ ASSERT_TRUE(blaze_util::WriteFile(
+ import_type + " " + dual_imported_rc_path,
+ intermediate_import_1, 0755));
+
+ const std::string intermediate_import_2 =
+ blaze_util::JoinPath(workspace_, "intermediate_import_2");
+ ASSERT_TRUE(blaze_util::WriteFile(
+ import_type + " " + dual_imported_rc_path,
+ intermediate_import_2, 0755));
+
+ // Import the custom location twice.
+ std::string workspace_rc;
+ ASSERT_TRUE(SetUpWorkspaceRcFile(
+ import_type + " " + intermediate_import_1 + "\n" +
+ import_type + " " + intermediate_import_2 + "\n",
+ &workspace_rc));
+
+ const std::vector<std::string> args = {"bazel", "build"};
+ ParseOptionsAndCheckOutput(
+ args, blaze_exit_code::SUCCESS, "",
+ "WARNING: Duplicate rc file: .*dual_imported.bazelrc is imported "
+ "multiple times from .*workspace.*bazelrc\n");
+ }
+
+ void TestThatImportingAFileAndPassingItInCausesAWarning(
+ const std::string& import_type) {
+ const std::string imported_rc_path =
+ blaze_util::JoinPath(workspace_, "myimportedbazelrc");
+ ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
+
+ // Import the custom location, and pass it in by flag.
+ std::string workspace_rc;
+ ASSERT_TRUE(
+ SetUpWorkspaceRcFile(
+ import_type + " " + imported_rc_path,
+ &workspace_rc));
+
+ const std::vector<std::string> args = {
+ "bazel", "--bazelrc=" + imported_rc_path, "build"};
+ ParseOptionsAndCheckOutput(
+ args, blaze_exit_code::SUCCESS, "",
+ "WARNING: Duplicate rc file: .*myimportedbazelrc is read multiple "
+ "times, "
+ "it is a standard rc file location but must have been unnecessarilly "
+ "imported earlier.\n");
+ }
+};
+
+TEST_F(BlazercImportTest, BazelRcImportFailsForMissingFile) {
const std::string missing_imported_rc_path =
blaze_util::JoinPath(workspace_, "myimportedbazelrc");
std::string workspace_rc;
@@ -673,77 +795,76 @@
"Unexpected error reading .blazerc file '.*myimportedbazelrc'", "");
}
-TEST_F(ParseOptionsTest, DoubleImportsCauseAWarning) {
- const std::string imported_rc_path =
- blaze_util::JoinPath(workspace_, "myimportedbazelrc");
- ASSERT_TRUE(
- blaze_util::MakeDirectories(blaze_util::Dirname(imported_rc_path), 0755));
- ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
-
- // Import the custom location twice.
+TEST_F(BlazercImportTest, BazelRcTryImportDoesNotFailForMissingFile) {
+ const std::string missing_imported_rc_path =
+ blaze_util::JoinPath(workspace_, "tryimported.bazelrc");
std::string workspace_rc;
- ASSERT_TRUE(SetUpWorkspaceRcFile(
- "import " + imported_rc_path + "\n"
- "import " + imported_rc_path + "\n",
- &workspace_rc));
+ ASSERT_TRUE(SetUpWorkspaceRcFile("try-import " + missing_imported_rc_path,
+ &workspace_rc));
const std::vector<std::string> args = {"bazel", "build"};
- ParseOptionsAndCheckOutput(
- args, blaze_exit_code::SUCCESS, "",
- "WARNING: Duplicate rc file: .*myimportedbazelrc is imported multiple "
- "times from .*workspace.*bazelrc\n");
+ ParseOptionsAndCheckOutput(args, blaze_exit_code::SUCCESS, "", "");
}
-TEST_F(ParseOptionsTest, DoubleImportWithWorkspaceRelativeSyntaxCauseAWarning) {
- const std::string imported_rc_path =
- blaze_util::JoinPath(workspace_, "myimportedbazelrc");
- ASSERT_TRUE(
- blaze_util::MakeDirectories(blaze_util::Dirname(imported_rc_path), 0755));
- ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
-
- // Import the custom location twice.
+// rc_file does not differentiate between non-existent and unreadable files. We
+// don't necessarily want try-import to ignore unreadable files, but this test
+// exists to make sure we don't change the behavior by accident. Any change that
+// makes existent but unreadable files a failure with try-import should inform
+// users.
+TEST_F(BlazercImportTest, BazelRcTryImportDoesNotFailForUnreadableFile) {
+ const std::string unreadable_rc_path =
+ blaze_util::JoinPath(workspace_, "tryimported.bazelrc");
+ ASSERT_TRUE(blaze_util::WriteFile("startup --max_idle_secs=123",
+ unreadable_rc_path, 222));
std::string workspace_rc;
- ASSERT_TRUE(SetUpWorkspaceRcFile(
- "import " + imported_rc_path + "\n"
- "import %workspace%/myimportedbazelrc\n",
- &workspace_rc));
+ ASSERT_TRUE(
+ SetUpWorkspaceRcFile("try-import " + unreadable_rc_path, &workspace_rc));
const std::vector<std::string> args = {"bazel", "build"};
- ParseOptionsAndCheckOutput(
- args, blaze_exit_code::SUCCESS, "",
- "WARNING: Duplicate rc file: .*myimportedbazelrc is imported multiple "
- "times from .*workspace.*bazelrc\n");
+ ParseOptionsAndCheckOutput(args, blaze_exit_code::SUCCESS, "", "");
}
-TEST_F(ParseOptionsTest, DoubleImportWithExcessPathSyntaxCauseAWarning) {
- const std::string imported_rc_path =
- blaze_util::JoinPath(workspace_, "myimportedbazelrc");
- ASSERT_TRUE(
- blaze_util::MakeDirectories(blaze_util::Dirname(imported_rc_path), 0755));
- ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
- // Import the custom location twice.
- std::string workspace_rc;
- ASSERT_TRUE(SetUpWorkspaceRcFile(
- "import " + imported_rc_path + "\n"
- "import %workspace%///.//myimportedbazelrc\n",
- &workspace_rc));
+TEST_F(BlazercImportTest, BazelRcImportsMaintainsFlagOrdering) {
+ TestBazelRcImportsMaintainsFlagOrdering("import");
+}
- const std::vector<std::string> args = {"bazel", "build"};
- ParseOptionsAndCheckOutput(
- args, blaze_exit_code::SUCCESS, "",
- "WARNING: Duplicate rc file: .*myimportedbazelrc is imported multiple "
- "times from .*workspace.*bazelrc\n");
+TEST_F(BlazercImportTest, BazelRcTryImportsMaintainsFlagOrdering) {
+ TestBazelRcImportsMaintainsFlagOrdering("try-import");
+}
+
+TEST_F(BlazercImportTest, DoubleImportsCauseAWarning) {
+ TestThatDoubleImportsCauseAWarning("import");
+}
+
+TEST_F(BlazercImportTest, DoubleTryImportsCauseAWarning) {
+ TestThatDoubleImportsCauseAWarning("try-import");
+}
+
+TEST_F(BlazercImportTest,
+ DoubleImportWithWorkspaceRelativeSyntaxCauseAWarning) {
+ TestThatDoubleImportWithWorkspaceRelativeSyntaxCauseAWarning("import");
+}
+
+TEST_F(BlazercImportTest,
+ DoubleTryImportWithWorkspaceRelativeSyntaxCauseAWarning) {
+ TestThatDoubleImportWithWorkspaceRelativeSyntaxCauseAWarning("try-import");
+}
+
+TEST_F(BlazercImportTest, DoubleImportWithExcessPathSyntaxCauseAWarning) {
+ TestThatDoubleImportWithExcessPathSyntaxCauseAWarning("import");
+}
+
+TEST_F(BlazercImportTest, DoubleTryImportWithExcessPathSyntaxCauseAWarning) {
+ TestThatDoubleImportWithExcessPathSyntaxCauseAWarning("try-import");
}
// The following tests unix-path semantics.
#if !defined(_WIN32) && !defined(__CYGWIN__)
-TEST_F(ParseOptionsTest,
+TEST_F(BlazercImportTest,
DoubleImportWithEnclosingDirectorySyntaxCauseAWarning) {
const std::string imported_rc_path =
blaze_util::JoinPath(workspace_, "myimportedbazelrc");
- ASSERT_TRUE(
- blaze_util::MakeDirectories(blaze_util::Dirname(imported_rc_path), 0755));
ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
ASSERT_TRUE(blaze_util::MakeDirectories(
@@ -764,61 +885,20 @@
}
#endif // !defined(_WIN32) && !defined(__CYGWIN__)
-TEST_F(ParseOptionsTest, DeepDoubleImportCausesAWarning) {
- const std::string dual_imported_rc_path =
- blaze_util::JoinPath(workspace_, "dual_imported.bazelrc");
- ASSERT_TRUE(blaze_util::MakeDirectories(
- blaze_util::Dirname(dual_imported_rc_path), 0755));
- ASSERT_TRUE(blaze_util::WriteFile("", dual_imported_rc_path, 0755));
-
- const std::string intermediate_import_1 =
- blaze_util::JoinPath(workspace_, "intermediate_import_1");
- ASSERT_TRUE(blaze_util::MakeDirectories(
- blaze_util::Dirname(intermediate_import_1), 0755));
- ASSERT_TRUE(blaze_util::WriteFile("import " + dual_imported_rc_path,
- intermediate_import_1, 0755));
-
- const std::string intermediate_import_2 =
- blaze_util::JoinPath(workspace_, "intermediate_import_2");
- ASSERT_TRUE(blaze_util::MakeDirectories(
- blaze_util::Dirname(intermediate_import_2), 0755));
- ASSERT_TRUE(blaze_util::WriteFile("import " + dual_imported_rc_path,
- intermediate_import_2, 0755));
-
- // Import the custom location twice.
- std::string workspace_rc;
- ASSERT_TRUE(SetUpWorkspaceRcFile(
- "import " + intermediate_import_1 + "\n"
- "import " + intermediate_import_2 + "\n",
- &workspace_rc));
-
- const std::vector<std::string> args = {"bazel", "build"};
- ParseOptionsAndCheckOutput(args, blaze_exit_code::SUCCESS, "",
- "WARNING: Duplicate rc file: "
- ".*dual_imported.bazelrc is imported multiple "
- "times from .*workspace.*bazelrc\n");
+TEST_F(BlazercImportTest, DeepDoubleImportCausesAWarning) {
+ TestThatDeepDoubleImportCausesAWarning("import");
}
+TEST_F(BlazercImportTest, DeepDoubleTryImportCausesAWarning) {
+ TestThatDeepDoubleImportCausesAWarning("try-import");
+}
-TEST_F(ParseOptionsTest, ImportingAFileAndPassingItInCausesAWarning) {
- const std::string imported_rc_path =
- blaze_util::JoinPath(workspace_, "myimportedbazelrc");
- ASSERT_TRUE(
- blaze_util::MakeDirectories(blaze_util::Dirname(imported_rc_path), 0755));
- ASSERT_TRUE(blaze_util::WriteFile("", imported_rc_path, 0755));
+TEST_F(BlazercImportTest, ImportingAFileAndPassingItInCausesAWarning) {
+ TestThatImportingAFileAndPassingItInCausesAWarning("import");
+}
- // Import the custom location, and pass it in by flag.
- std::string workspace_rc;
- ASSERT_TRUE(
- SetUpWorkspaceRcFile("import " + imported_rc_path, &workspace_rc));
-
- const std::vector<std::string> args = {
- "bazel", "--bazelrc=" + imported_rc_path, "build"};
- ParseOptionsAndCheckOutput(
- args, blaze_exit_code::SUCCESS, "",
- "WARNING: Duplicate rc file: .*myimportedbazelrc is read multiple times, "
- "it is a standard rc file location but must have been unnecessarilly "
- "imported earlier.\n");
+TEST_F(BlazercImportTest, TryImportingAFileAndPassingItInCausesAWarning) {
+ TestThatImportingAFileAndPassingItInCausesAWarning("try-import");
}
// TODO(b/112908763): Somehow, in the following tests, we end with a relative
diff --git a/src/test/cpp/rc_options_test.cc b/src/test/cpp/rc_options_test.cc
index 41684a5..daaba7f 100644
--- a/src/test/cpp/rc_options_test.cc
+++ b/src/test/cpp/rc_options_test.cc
@@ -88,8 +88,6 @@
}
};
-// Effectively empty file tests
-
TEST_F(RcOptionsTest, Empty) {
WriteRc("empty.bazelrc",
"");
@@ -127,8 +125,6 @@
no_expected_args);
}
-// Single command tests - testing tokenization and accumulation of arguments.
-
TEST_F(RcOptionsTest, SingleStartupArg) {
WriteRc("startup_foo.bazelrc",
"startup foo");
@@ -249,8 +245,6 @@
}});
}
-// Testing which commands different args belong to.
-
TEST_F(RcOptionsTest, MultipleCommands) {
WriteRc("multiple_commands_intermixed.bazelrc",
"startup foo\n"
@@ -263,8 +257,6 @@
{{"startup", {"foo", "bar", "baz"}}, {"build", {"aaa", "bbb", "ccc"}}});
}
-// Successful import tests
-
TEST_F(RcOptionsTest, SimpleImportFoo) {
WriteRc("startup_foo.bazelrc",
"startup foo");
@@ -297,9 +289,36 @@
{{"startup", {"bar", "foo"}}});
}
-// Consider making this an error, or at least a warning - most likely, import
-// diamonds like this are unintended, and they might lead to surprising doubled
-// values for allow_multiple options.
+TEST_F(RcOptionsTest, SimpleTryImportFoo) {
+ WriteRc("startup_foo.bazelrc", "startup foo");
+ WriteRc("import_simple.bazelrc",
+ "try-import %workspace%/startup_foo.bazelrc");
+ SuccessfullyParseRcWithExpectedArgs("import_simple.bazelrc",
+ {{"startup", {"foo"}}});
+}
+
+TEST_F(RcOptionsTest, ImportTryFooThenAddBar) {
+ WriteRc("startup_foo.bazelrc", "startup foo");
+ WriteRc("import_foo_then_bar.bazelrc",
+ "try-import %workspace%/startup_foo.bazelrc\n"
+ "startup bar");
+ SuccessfullyParseRcWithExpectedArgs("import_foo_then_bar.bazelrc",
+ {{"startup", {"foo", "bar"}}});
+}
+
+TEST_F(RcOptionsTest, StartupBarThenTryImportFoo) {
+ WriteRc("startup_foo.bazelrc", "startup foo");
+ WriteRc("bar_then_import_foo.bazelrc",
+ "startup bar\n"
+ "try-import %workspace%/startup_foo.bazelrc");
+ SuccessfullyParseRcWithExpectedArgs("bar_then_import_foo.bazelrc",
+ {{"startup", {"bar", "foo"}}});
+}
+
+// Most likely, import diamonds like this are unintended, and they might lead
+// to surprising doubled values for allow_multiple options. This causes a
+// warning in option_processor, which checks for duplicates across multiple rc
+// files.
TEST_F(RcOptionsTest, ImportDiamond) {
WriteRc("startup_foo.bazelrc",
"startup foo");
@@ -317,7 +336,6 @@
{{"startup", {"foo", "bar", "bar", "foo"}}});
}
-// Testing failure modes
TEST_F(RcOptionsTest, ImportCycleFails) {
WriteRc("import_cycle_1.bazelrc",
@@ -392,6 +410,14 @@
ASSERT_EQ(error_text, "Unexpected error reading .blazerc file 'somefile'");
}
+TEST_F(RcOptionsTest, TryImportedFileDoesNotExist) {
+ WriteRc("try_import_fake_file.bazelrc", "try-import somefile");
+
+ unordered_map<string, vector<string>> no_expected_args;
+ SuccessfullyParseRcWithExpectedArgs("try_import_fake_file.bazelrc",
+ no_expected_args);
+}
+
TEST_F(RcOptionsTest, ImportHasTooManyArgs) {
WriteRc("bad_import.bazelrc",
"import somefile bar");
@@ -407,6 +433,20 @@
"in your source checkout/WORKSPACE\\?\\)"));
}
+TEST_F(RcOptionsTest, TryImportHasTooManyArgs) {
+ WriteRc("bad_import.bazelrc", "try-import somefile bar");
+
+ RcFile::ParseError error;
+ string error_text;
+ std::unique_ptr<RcFile> rc = Parse("bad_import.bazelrc", &error, &error_text);
+ EXPECT_EQ(error, RcFile::ParseError::INVALID_FORMAT);
+ ASSERT_THAT(
+ error_text,
+ MatchesRegex("Invalid import declaration in .blazerc file "
+ "'.*bad_import.bazelrc': 'try-import somefile bar' \\(are "
+ "you in your source checkout/WORKSPACE\\?\\)"));
+}
+
// TODO(b/34811299) The tests below identify ways that '\' used as a line
// continuation is broken. This is on top of user-reported cases where an
// unintentional '\' made the command on the following line show up as