Skip to content

Commit c0075e8

Browse files
committed
Add support for %bazel.version*% variables in bazelrc imports
Follows the proposal: #24043 (comment) by mattyclarkson@ to add support for the following variables when importing additional bazelrc files: - %bazel.version% - %bazel.version.major% - %bazel.version.minor% - %bazel.version.patch% Eg. If your bazel version was 8.4.2 and your .bazelrc had the following: > try-import %bazel.version%.bazelrc > import %bazel.version.major%.%bazel.version.minor%-%bazel.version.patch%.bazelrc > try-import %bazel.version.major%.bazelrc It would be evaluated to: > try-import 8.4.2.bazelrc > import 8.4-2.bazelrc > try-import 8.bazelrc # Implementation details: ## Build label extraction: Before: The build label was extracted out only when calling `bazel --version` and when running in client server mode. After: Now we always extract the the build label out early in the start of main ## Piping of build label: The build label is stored in the OptionProcessor so that it can be passed to `RcFile` when parsing occurs. ## Parsing and mapping of variables: The build label is parsed during `RcFile::ParseFile` into its constituent parts (major, minor, patch). This occurs EACH TIME an import statement is found in a .rc file. This is wasteful, but the logic is simple enough that it shouldn't matter. Interpolation of the build label happens first, followed by `%workspace%`. Fixes: #24043
1 parent acac65d commit c0075e8

File tree

8 files changed

+203
-25
lines changed

8 files changed

+203
-25
lines changed

src/main/cpp/blaze.cc

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,9 +1481,7 @@ void PrintBazelLeaf() {
14811481
printf("%s\n", leaf.c_str());
14821482
}
14831483

1484-
void PrintVersionInfo(const string &self_path, const string &product_name) {
1485-
string build_label;
1486-
ExtractBuildLabel(self_path, &build_label);
1484+
void PrintVersionInfo(const string &build_label, const string &product_name) {
14871485
printf("%s %s\n", product_name.c_str(), build_label.c_str());
14881486
}
14891487

@@ -1495,7 +1493,8 @@ static void RunLauncher(const string &self_path,
14951493
const WorkspaceLayout &workspace_layout,
14961494
const string &workspace, LoggingInfo *logging_info,
14971495
StartupInterceptor *interceptor,
1498-
CommandExtensionAdder *command_extension_adder) {
1496+
CommandExtensionAdder *command_extension_adder,
1497+
const string &build_label) {
14991498
blaze_server = new BlazeServer(startup_options, command_extension_adder);
15001499

15011500
const std::optional<DurationMillis> command_wait_duration =
@@ -1566,8 +1565,6 @@ static void RunLauncher(const string &self_path,
15661565
option_processor, startup_options, logging_info,
15671566
extract_data_duration, command_wait_duration, blaze_server);
15681567
} else {
1569-
string build_label;
1570-
ExtractBuildLabel(self_path, &build_label);
15711568
RunClientServerMode(
15721569
server_exe, server_exe_args, server_dir, workspace_layout, workspace,
15731570
option_processor, startup_options, logging_info, extract_data_duration,
@@ -1593,8 +1590,15 @@ int Main(int argc, const char *const *argv, WorkspaceLayout *workspace_layout,
15931590
return blaze_exit_code::SUCCESS;
15941591
}
15951592

1593+
// Extract build_label to be used in two places:
1594+
// 1) PrintVersionInfo()
1595+
// 2) Resolving %bazel.version*% variables in .bazelrc files.
1596+
string build_label;
1597+
ExtractBuildLabel(self_path, &build_label);
1598+
option_processor->SetBuildLabel(build_label);
1599+
15961600
if (argc == 2 && strcmp(argv[1], "--version") == 0) {
1597-
PrintVersionInfo(self_path, option_processor->GetLowercaseProductName());
1601+
PrintVersionInfo(build_label, option_processor->GetLowercaseProductName());
15981602
return blaze_exit_code::SUCCESS;
15991603
}
16001604

@@ -1671,7 +1675,7 @@ int Main(int argc, const char *const *argv, WorkspaceLayout *workspace_layout,
16711675

16721676
RunLauncher(self_path, archive_contents, install_md5, *startup_options,
16731677
*option_processor, *workspace_layout, workspace, &logging_info,
1674-
interceptor, command_extension_adder);
1678+
interceptor, command_extension_adder, build_label);
16751679
return 0;
16761680
}
16771681

src/main/cpp/blaze.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace blaze {
2626

2727
// Prints client version information to standard output, e.g. when invoking the
2828
// client with "--version".
29-
void PrintVersionInfo(const std::string& self_path,
29+
void PrintVersionInfo(const std::string& build_label,
3030
const std::string& product_name);
3131

3232
int Main(int argc, const char* const* argv, WorkspaceLayout* workspace_layout,

src/main/cpp/option_processor.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,8 @@ blaze_exit_code::ExitCode OptionProcessor::GetRcFiles(
447447
for (const std::string& top_level_bazelrc_path : rc_files) {
448448
std::unique_ptr<RcFile> parsed_rc;
449449
blaze_exit_code::ExitCode parse_rcfile_exit_code = ParseRcFile(
450-
workspace_layout, workspace, top_level_bazelrc_path, &parsed_rc, error);
450+
workspace_layout, workspace, top_level_bazelrc_path, build_label_,
451+
&parsed_rc, error);
451452
if (parse_rcfile_exit_code != blaze_exit_code::SUCCESS) {
452453
return parse_rcfile_exit_code;
453454
}
@@ -488,14 +489,16 @@ blaze_exit_code::ExitCode OptionProcessor::GetRcFiles(
488489
blaze_exit_code::ExitCode ParseRcFile(const WorkspaceLayout* workspace_layout,
489490
const std::string& workspace,
490491
const std::string& rc_file_path,
492+
const std::string& build_label,
491493
std::unique_ptr<RcFile>* result_rc_file,
492494
std::string* error) {
493495
assert(!rc_file_path.empty());
494496
assert(result_rc_file != nullptr);
495497

496498
RcFile::ParseError parse_error;
497499
std::unique_ptr<RcFile> parsed_file = RcFile::Parse(
498-
rc_file_path, workspace_layout, workspace, &parse_error, error);
500+
rc_file_path, workspace_layout, workspace, &parse_error, error,
501+
build_label);
499502
if (parsed_file == nullptr) {
500503
return internal::ParseErrorToExitCode(parse_error);
501504
}

src/main/cpp/option_processor.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ class OptionProcessor {
127127
// the failure. Otherwise, the server will handle any required logging.
128128
void PrintStartupOptionsProvenanceMessage() const;
129129

130+
// Sets the build label.
131+
void SetBuildLabel(const std::string &build_label) {
132+
build_label_ = build_label;
133+
}
134+
130135
// Parse the files in `blazercs` and return all options that need to be passed
131136
// to the server. The options are returned in the order they should be appear
132137
// on the command line (later options have precedence over earlier ones).
@@ -180,12 +185,16 @@ class OptionProcessor {
180185
// Path to the system-wide bazelrc configuration file.
181186
// This is configurable for testing purposes only.
182187
const std::string system_bazelrc_path_;
188+
189+
// Build label for Bazel.
190+
std::string build_label_;
183191
};
184192

185193
// Parses and returns the contents of the rc file.
186194
blaze_exit_code::ExitCode ParseRcFile(const WorkspaceLayout* workspace_layout,
187195
const std::string& workspace,
188196
const std::string& rc_file_path,
197+
const std::string& build_label,
189198
std::unique_ptr<RcFile>* result_rc_file,
190199
std::string* error);
191200

src/main/cpp/rc_file.cc

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "absl/strings/match.h"
3232
#include "absl/strings/str_cat.h"
3333
#include "absl/strings/str_format.h"
34+
#include "absl/strings/str_replace.h"
3435
#include "absl/strings/str_split.h"
3536
#include "absl/strings/string_view.h"
3637
#include "absl/types/span.h"
@@ -43,18 +44,20 @@ static constexpr absl::string_view kCommandTryImport = "try-import";
4344
/*static*/ std::unique_ptr<RcFile> RcFile::Parse(
4445
const std::string& filename, const WorkspaceLayout* workspace_layout,
4546
const std::string& workspace, ParseError* error, std::string* error_text,
46-
ReadFileFn read_file, CanonicalizePathFn canonicalize_path) {
47+
const std::string& build_label, ReadFileFn read_file,
48+
CanonicalizePathFn canonicalize_path) {
4749
auto rcfile = absl::WrapUnique(new RcFile());
4850
std::vector<std::string> initial_import_stack = {filename};
49-
*error = rcfile->ParseFile(filename, workspace, *workspace_layout, read_file,
50-
canonicalize_path, initial_import_stack,
51-
error_text);
51+
*error = rcfile->ParseFile(filename, workspace, *workspace_layout,
52+
build_label, read_file, canonicalize_path,
53+
initial_import_stack, error_text);
5254
return (*error == ParseError::NONE) ? std::move(rcfile) : nullptr;
5355
}
5456

5557
RcFile::ParseError RcFile::ParseFile(const std::string& filename,
5658
const std::string& workspace,
5759
const WorkspaceLayout& workspace_layout,
60+
const std::string& build_label,
5861
ReadFileFn read_file,
5962
CanonicalizePathFn canonicalize_path,
6063
std::vector<std::string>& import_stack,
@@ -109,17 +112,24 @@ RcFile::ParseError RcFile::ParseFile(const std::string& filename,
109112
return ParseError::INVALID_FORMAT;
110113
}
111114

112-
std::string& import_filename = words[1];
115+
std::string import_filename = ReplaceBuildVars(build_label, words[1]);
113116
if (absl::StartsWith(import_filename, WorkspaceLayout::kWorkspacePrefix)) {
114117
const auto resolved_filename =
115118
workspace_layout.ResolveWorkspaceRelativeRcFilePath(workspace,
116119
import_filename);
117120
if (!resolved_filename.has_value()) {
118121
if (command == kCommandImport) {
122+
// If build variables were replaced in the filename, print out the
123+
// evaluated path so they know the file lookup that was attempted.
124+
std::string evaluated_line = ReplaceBuildVars(build_label, line);
125+
std::string evaluated_warning;
126+
if (line != evaluated_line) {
127+
evaluated_warning = absl::StrFormat("file evaluated to '%s' - ", evaluated_line);
128+
}
119129
*error_text = absl::StrFormat(
120130
"Nonexistent path in import declaration in config file '%s': '%s'"
121-
" (are you in your source checkout/WORKSPACE?)",
122-
canonical_filename, line);
131+
" (%sare you in your source checkout/WORKSPACE?)",
132+
canonical_filename, line, evaluated_warning);
123133
return ParseError::INVALID_FORMAT;
124134
}
125135
// For try-import, we ignore it if we couldn't find a file.
@@ -144,8 +154,8 @@ RcFile::ParseError RcFile::ParseFile(const std::string& filename,
144154

145155
import_stack.push_back(import_filename);
146156
if (ParseError parse_error =
147-
ParseFile(import_filename, workspace, workspace_layout, read_file,
148-
canonicalize_path, import_stack, error_text);
157+
ParseFile(import_filename, workspace, workspace_layout, build_label,
158+
read_file, canonicalize_path, import_stack, error_text);
149159
parse_error != ParseError::NONE) {
150160
if (parse_error == ParseError::UNREADABLE_FILE &&
151161
command == kCommandTryImport) {
@@ -176,4 +186,29 @@ std::string RcFile::CanonicalizePathDefault(const std::string& filename) {
176186
return blaze_util::MakeCanonical(filename.c_str());
177187
}
178188

189+
std::string ReplaceBuildVars(absl::string_view build_label,
190+
absl::string_view import_filename) {
191+
absl::string_view version;
192+
absl::string_view major;
193+
absl::string_view minor;
194+
absl::string_view patch;
195+
std::vector<absl::string_view> v =
196+
absl::StrSplit(build_label, absl::MaxSplits('.', 2));
197+
if (v.size() == 3) {
198+
version = build_label;
199+
major = v.at(0);
200+
minor = v.at(1);
201+
patch = v.at(2);
202+
} else {
203+
version = kNoVersion;
204+
major = kNoVersion;
205+
minor = kNoVersion;
206+
patch = kNoVersion;
207+
}
208+
return absl::StrReplaceAll(import_filename, {{kBazelVersion, version},
209+
{kBazelVersionMajor, major},
210+
{kBazelVersionMinor, minor},
211+
{kBazelVersionPatch, patch}});
212+
}
213+
179214
} // namespace blaze

src/main/cpp/rc_file.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class RcFile {
4444
static std::unique_ptr<RcFile> Parse(
4545
const std::string& filename, const WorkspaceLayout* workspace_layout,
4646
const std::string& workspace, ParseError* error, std::string* error_text,
47-
ReadFileFn read_file = &ReadFileDefault,
47+
const std::string &build_label, ReadFileFn read_file = &ReadFileDefault,
4848
CanonicalizePathFn canonicalize_path = &CanonicalizePathDefault);
4949

5050
// Movable and copyable.
@@ -69,6 +69,7 @@ class RcFile {
6969
ParseError ParseFile(const std::string& filename,
7070
const std::string& workspace,
7171
const WorkspaceLayout& workspace_layout,
72+
const std::string& build_label,
7273
ReadFileFn read_file,
7374
CanonicalizePathFn canonicalize_path,
7475
std::vector<std::string>& import_stack,
@@ -86,6 +87,18 @@ class RcFile {
8687
OptionMap options_;
8788
};
8889

90+
// When the build label can't be parsed into a naive semantic version (three
91+
// strings separated by dots), this will be the value for the version name,
92+
// major, minor and patch.
93+
static constexpr char kNoVersion[] = "no_version";
94+
// Variables that can be interpolated in .bazelrc when importing files.
95+
static constexpr char kBazelVersion[] = "%bazel.version%";
96+
static constexpr char kBazelVersionMajor[] = "%bazel.version.major%";
97+
static constexpr char kBazelVersionMinor[] = "%bazel.version.minor%";
98+
static constexpr char kBazelVersionPatch[] = "%bazel.version.patch%";
99+
std::string ReplaceBuildVars(absl::string_view build_label,
100+
absl::string_view import_filename);
101+
89102
} // namespace blaze
90103

91104
#endif // BAZEL_SRC_MAIN_CPP_RC_FILE_H_

0 commit comments

Comments
 (0)