Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/main/cpp/blaze.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1481,9 +1481,7 @@ void PrintBazelLeaf() {
printf("%s\n", leaf.c_str());
}

void PrintVersionInfo(const string &self_path, const string &product_name) {
string build_label;
ExtractBuildLabel(self_path, &build_label);
void PrintVersionInfo(const string &build_label, const string &product_name) {
printf("%s %s\n", product_name.c_str(), build_label.c_str());
}

Expand All @@ -1495,7 +1493,8 @@ static void RunLauncher(const string &self_path,
const WorkspaceLayout &workspace_layout,
const string &workspace, LoggingInfo *logging_info,
StartupInterceptor *interceptor,
CommandExtensionAdder *command_extension_adder) {
CommandExtensionAdder *command_extension_adder,
const string &build_label) {
blaze_server = new BlazeServer(startup_options, command_extension_adder);

const std::optional<DurationMillis> command_wait_duration =
Expand Down Expand Up @@ -1566,8 +1565,6 @@ static void RunLauncher(const string &self_path,
option_processor, startup_options, logging_info,
extract_data_duration, command_wait_duration, blaze_server);
} else {
string build_label;
ExtractBuildLabel(self_path, &build_label);
RunClientServerMode(
server_exe, server_exe_args, server_dir, workspace_layout, workspace,
option_processor, startup_options, logging_info, extract_data_duration,
Expand All @@ -1593,8 +1590,15 @@ int Main(int argc, const char *const *argv, WorkspaceLayout *workspace_layout,
return blaze_exit_code::SUCCESS;
}

// Extract build_label to be used in two places:
// 1) PrintVersionInfo()
// 2) Resolving %bazel.version*% variables in .bazelrc files.
string build_label;
ExtractBuildLabel(self_path, &build_label);
option_processor->SetBuildLabel(build_label);

if (argc == 2 && strcmp(argv[1], "--version") == 0) {
PrintVersionInfo(self_path, option_processor->GetLowercaseProductName());
PrintVersionInfo(build_label, option_processor->GetLowercaseProductName());
return blaze_exit_code::SUCCESS;
}

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

RunLauncher(self_path, archive_contents, install_md5, *startup_options,
*option_processor, *workspace_layout, workspace, &logging_info,
interceptor, command_extension_adder);
interceptor, command_extension_adder, build_label);
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/cpp/blaze.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace blaze {

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

int Main(int argc, const char* const* argv, WorkspaceLayout* workspace_layout,
Expand Down
18 changes: 16 additions & 2 deletions src/main/cpp/option_processor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,8 @@ blaze_exit_code::ExitCode OptionProcessor::GetRcFiles(
for (const std::string& top_level_bazelrc_path : rc_files) {
std::unique_ptr<RcFile> parsed_rc;
blaze_exit_code::ExitCode parse_rcfile_exit_code = ParseRcFile(
workspace_layout, workspace, top_level_bazelrc_path, &parsed_rc, error);
workspace_layout, workspace, top_level_bazelrc_path, build_label_,
&parsed_rc, error);
if (parse_rcfile_exit_code != blaze_exit_code::SUCCESS) {
return parse_rcfile_exit_code;
}
Expand Down Expand Up @@ -485,17 +486,30 @@ blaze_exit_code::ExitCode OptionProcessor::GetRcFiles(
return blaze_exit_code::SUCCESS;
}

// When the build label can't be parsed into a proper semantic version (per
// semver.org), this will be the value for each semantic variable part.
constexpr char kNoVersion[] = "no_version";

blaze_exit_code::ExitCode ParseRcFile(const WorkspaceLayout* workspace_layout,
const std::string& workspace,
const std::string& rc_file_path,
const std::string& build_label,
std::unique_ptr<RcFile>* result_rc_file,
std::string* error) {
assert(!rc_file_path.empty());
assert(result_rc_file != nullptr);

auto sem_ver = ParseSemVer(build_label);
if (!sem_ver.has_value()) {
// Couldn't parse a version, provide "no_version" values for a SemVer.
SemVer noVersionSemVer = {kNoVersion, kNoVersion};
sem_ver.emplace(noVersionSemVer);
}

RcFile::ParseError parse_error;
std::unique_ptr<RcFile> parsed_file = RcFile::Parse(
rc_file_path, workspace_layout, workspace, &parse_error, error);
rc_file_path, workspace_layout, workspace, &parse_error, error,
sem_ver.value());
if (parsed_file == nullptr) {
return internal::ParseErrorToExitCode(parse_error);
}
Expand Down
9 changes: 9 additions & 0 deletions src/main/cpp/option_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ class OptionProcessor {
// the failure. Otherwise, the server will handle any required logging.
void PrintStartupOptionsProvenanceMessage() const;

// Sets the build label.
void SetBuildLabel(const std::string &build_label) {
build_label_ = build_label;
}

// Parse the files in `blazercs` and return all options that need to be passed
// to the server. The options are returned in the order they should be appear
// on the command line (later options have precedence over earlier ones).
Expand Down Expand Up @@ -180,12 +185,16 @@ class OptionProcessor {
// Path to the system-wide bazelrc configuration file.
// This is configurable for testing purposes only.
const std::string system_bazelrc_path_;

// Build label for Bazel.
std::string build_label_;
};

// Parses and returns the contents of the rc file.
blaze_exit_code::ExitCode ParseRcFile(const WorkspaceLayout* workspace_layout,
const std::string& workspace,
const std::string& rc_file_path,
const std::string& build_label,
std::unique_ptr<RcFile>* result_rc_file,
std::string* error);

Expand Down
61 changes: 52 additions & 9 deletions src/main/cpp/rc_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <memory>
#include <optional>
#include <regex>
#include <string>
#include <utility>
#include <vector>
Expand All @@ -31,6 +32,7 @@
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
Expand All @@ -43,18 +45,20 @@ static constexpr absl::string_view kCommandTryImport = "try-import";
/*static*/ std::unique_ptr<RcFile> RcFile::Parse(
const std::string& filename, const WorkspaceLayout* workspace_layout,
const std::string& workspace, ParseError* error, std::string* error_text,
ReadFileFn read_file, CanonicalizePathFn canonicalize_path) {
const SemVer& sem_ver, ReadFileFn read_file,
CanonicalizePathFn canonicalize_path) {
auto rcfile = absl::WrapUnique(new RcFile());
std::vector<std::string> initial_import_stack = {filename};
*error = rcfile->ParseFile(filename, workspace, *workspace_layout, read_file,
canonicalize_path, initial_import_stack,
error_text);
*error = rcfile->ParseFile(filename, workspace, *workspace_layout,
sem_ver, read_file, canonicalize_path,
initial_import_stack, error_text);
return (*error == ParseError::NONE) ? std::move(rcfile) : nullptr;
}

RcFile::ParseError RcFile::ParseFile(const std::string& filename,
const std::string& workspace,
const WorkspaceLayout& workspace_layout,
const SemVer& sem_ver,
ReadFileFn read_file,
CanonicalizePathFn canonicalize_path,
std::vector<std::string>& import_stack,
Expand Down Expand Up @@ -109,17 +113,24 @@ RcFile::ParseError RcFile::ParseFile(const std::string& filename,
return ParseError::INVALID_FORMAT;
}

std::string& import_filename = words[1];
std::string import_filename = ReplaceBuildVars(sem_ver, words[1]);
if (absl::StartsWith(import_filename, WorkspaceLayout::kWorkspacePrefix)) {
const auto resolved_filename =
workspace_layout.ResolveWorkspaceRelativeRcFilePath(workspace,
import_filename);
if (!resolved_filename.has_value()) {
if (command == kCommandImport) {
// If build variables were replaced in the filename, print out the
// evaluated path so they know the file lookup that was attempted.
std::string evaluated_line = ReplaceBuildVars(sem_ver, line);
std::string evaluated_warning;
if (line != evaluated_line) {
evaluated_warning = absl::StrFormat("file evaluated to '%s' - ", evaluated_line);
}
*error_text = absl::StrFormat(
"Nonexistent path in import declaration in config file '%s': '%s'"
" (are you in your source checkout/WORKSPACE?)",
canonical_filename, line);
" (%sare you in your source checkout/WORKSPACE?)",
canonical_filename, line, evaluated_warning);
return ParseError::INVALID_FORMAT;
}
// For try-import, we ignore it if we couldn't find a file.
Expand All @@ -144,8 +155,8 @@ RcFile::ParseError RcFile::ParseFile(const std::string& filename,

import_stack.push_back(import_filename);
if (ParseError parse_error =
ParseFile(import_filename, workspace, workspace_layout, read_file,
canonicalize_path, import_stack, error_text);
ParseFile(import_filename, workspace, workspace_layout, sem_ver,
read_file, canonicalize_path, import_stack, error_text);
parse_error != ParseError::NONE) {
if (parse_error == ParseError::UNREADABLE_FILE &&
command == kCommandTryImport) {
Expand Down Expand Up @@ -175,5 +186,37 @@ bool RcFile::ReadFileDefault(const std::string& filename, std::string* contents,
std::string RcFile::CanonicalizePathDefault(const std::string& filename) {
return blaze_util::MakeCanonical(filename.c_str());
}
namespace {
// Variables that can be interpolated in .bazelrc when importing files.
constexpr char kBazelVersionMajor[] =
"%bazel.version.major%"; // Eg. "8" in 8.4.2
constexpr char kBazelVersionMajorMinor[] =
"%bazel.version.major.minor%"; // Eg. "8.4" in 8.4.2

// Semantic version regex copied verbatim from
// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
const std::regex kSemverRe(
R"(^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$)");
} // namespace

std::optional<SemVer> ParseSemVer(const std::string& build_label) {
if (std::smatch m; std::regex_match(build_label, m, kSemverRe)) {
SemVer sem_ver;
sem_ver.major = m[1];
sem_ver.minor = m[2];
return sem_ver;
}
return std::nullopt;
}

std::string ReplaceBuildVars(const SemVer& sem_ver,
absl::string_view import_filename) {
return absl::StrReplaceAll(
import_filename, {
{kBazelVersionMajor, sem_ver.major},
{kBazelVersionMajorMinor,
absl::StrCat(sem_ver.major, ".", sem_ver.minor)},
});
}

} // namespace blaze
18 changes: 17 additions & 1 deletion src/main/cpp/rc_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#define BAZEL_SRC_MAIN_CPP_RC_FILE_H_

#include <memory>
#include <regex>
#include <string>
#include <vector>

Expand All @@ -32,6 +33,13 @@ struct RcOption {
int source_index;
};

// Represents a semantic version. Only major and minor values are provided since
// those are the only ones used at the moment.
struct SemVer {
std::string major; // "8" in the semantic version "8.4.2"
std::string minor; // "4" in the semantic version "8.4.2"
};

// Reads and parses a single rc file with all its imports.
class RcFile {
public:
Expand All @@ -44,7 +52,7 @@ class RcFile {
static std::unique_ptr<RcFile> Parse(
const std::string& filename, const WorkspaceLayout* workspace_layout,
const std::string& workspace, ParseError* error, std::string* error_text,
ReadFileFn read_file = &ReadFileDefault,
const SemVer& build_label, ReadFileFn read_file = &ReadFileDefault,
CanonicalizePathFn canonicalize_path = &CanonicalizePathDefault);

// Movable and copyable.
Expand All @@ -69,6 +77,7 @@ class RcFile {
ParseError ParseFile(const std::string& filename,
const std::string& workspace,
const WorkspaceLayout& workspace_layout,
const SemVer& build_label,
ReadFileFn read_file,
CanonicalizePathFn canonicalize_path,
std::vector<std::string>& import_stack,
Expand All @@ -86,6 +95,13 @@ class RcFile {
OptionMap options_;
};


// Parses a version string and returns a structured SemVer. If the argument is
// not a valid semantic version per semver.org, returns nullopt.
std::optional<SemVer> ParseSemVer(const std::string& build_label);

std::string ReplaceBuildVars(const SemVer& sem_ver,
absl::string_view import_filename);
} // namespace blaze

#endif // BAZEL_SRC_MAIN_CPP_RC_FILE_H_
Loading