// Copyright 2018 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/main/cpp/rc_file.h" #include #include #include "src/main/cpp/blaze_util.h" #include "src/main/cpp/blaze_util_platform.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" #include "src/main/cpp/util/strings.h" #include "src/main/cpp/workspace_layout.h" namespace blaze { using std::deque; using std::string; using std::vector; RcFile::RcFile(string filename, const WorkspaceLayout* workspace_layout, string workspace) : filename_(std::move(filename)), workspace_layout_(workspace_layout), workspace_(std::move(workspace)) {} /*static*/ std::unique_ptr RcFile::Parse( std::string filename, const WorkspaceLayout* workspace_layout, std::string workspace, ParseError* error, std::string* error_text) { std::unique_ptr rcfile(new RcFile( std::move(filename), workspace_layout, std::move(workspace))); deque initial_import_stack = {rcfile->filename_}; *error = rcfile->ParseFile( rcfile->filename_, &initial_import_stack, error_text); return (*error == ParseError::NONE) ? std::move(rcfile) : nullptr; } RcFile::ParseError RcFile::ParseFile(const string& filename, deque* import_stack, string* error_text) { BAZEL_LOG(INFO) << "Parsing the RcFile " << filename; string contents; if (!blaze_util::ReadFile(filename, &contents)) { blaze_util::StringPrintf(error_text, "Unexpected error reading .blazerc file '%s'", filename.c_str()); return ParseError::UNREADABLE_FILE; } rcfile_paths_.push_back(filename); // Keep a pointer to the filename string in rcfile_paths_ for the RcOptions. string* filename_ptr = &rcfile_paths_.back(); // A '\' at the end of a line continues the line. blaze_util::Replace("\\\r\n", "", &contents); blaze_util::Replace("\\\n", "", &contents); vector lines = blaze_util::Split(contents, '\n'); for (string& line : lines) { blaze_util::StripWhitespace(&line); // Check for an empty line. if (line.empty()) { continue; } vector words; // This will treat "#" as a comment, and properly // quote single and double quotes, and treat '\' // as an escape character. // TODO(bazel-team): This function silently ignores // dangling backslash escapes and missing end-quotes. blaze_util::Tokenize(line, '#', &words); if (words.empty()) { // Could happen if line starts with "#" continue; } string command = words[0]; if (command == "import") { if (words.size() != 2 || (words[1].compare(0, workspace_layout_->WorkspacePrefixLength, workspace_layout_->WorkspacePrefix) == 0 && !workspace_layout_->WorkspaceRelativizeRcFilePath(workspace_, &words[1]))) { blaze_util::StringPrintf( error_text, "Invalid import declaration in .blazerc file '%s': '%s'" " (are you in your source checkout/WORKSPACE?)", filename.c_str(), line.c_str()); return ParseError::INVALID_FORMAT; } if (std::find(import_stack->begin(), import_stack->end(), words[1]) != import_stack->end()) { string loop; for (const string& imported_rc : *import_stack) { loop += " " + imported_rc + "\n"; } loop += " " + words[1] + "\n"; // Include the loop. blaze_util::StringPrintf(error_text, "Import loop detected:\n%s", loop.c_str()); return ParseError::IMPORT_LOOP; } import_stack->push_back(words[1]); ParseError parse_error = ParseFile(words[1], import_stack, error_text); if (parse_error != ParseError::NONE) { return parse_error; } import_stack->pop_back(); } else { auto words_it = words.begin(); words_it++; // Advance past command. for (; words_it != words.end(); words_it++) { options_[command].push_back({filename_ptr, *words_it}); } } } return ParseError::NONE; } } // namespace blaze