Skip to content

Commit

Permalink
Fix possible parsing of same rc file multiple times.
Browse files Browse the repository at this point in the history
Write a new function that dedupes a set of paths using its canonical
form and use it to remove possible duplicates in the set of rc files
that will be parsed.
PiperOrigin-RevId: 152489149
  • Loading branch information
lfpino authored and hlopko committed Apr 7, 2017
1 parent fa36227 commit b379f65
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 13 deletions.
34 changes: 34 additions & 0 deletions src/main/cpp/option_processor-internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2017 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.

#ifndef THIRD_PARTY_BAZEL_SRC_MAIN_CPP_OPTION_PROCESSOR_INTERNAL_H_
#define THIRD_PARTY_BAZEL_SRC_MAIN_CPP_OPTION_PROCESSOR_INTERNAL_H_

#include <algorithm>

#include "src/main/cpp/util/file.h"

namespace blaze {
namespace internal {

// Returns the deduped set of blazerc paths (with respect to its canonical form)
// preserving the original order. The paths that cannot be resolved are
// omitted.
std::vector<std::string> DedupeBlazercPaths(
const std::vector<std::string>& paths);

} // namespace internal
} // namespace blaze

#endif // THIRD_PARTY_BAZEL_SRC_MAIN_CPP_OPTION_PROCESSOR_INTERNAL_H_
45 changes: 32 additions & 13 deletions src/main/cpp/option_processor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,26 @@ blaze_exit_code::ExitCode OptionProcessor::FindUserBlazerc(
return blaze_exit_code::SUCCESS;
}

namespace internal {
vector<string> DedupeBlazercPaths(const vector<string>& paths) {
set<string> canonical_paths;
vector<string> result;
for (const string& path : paths) {
const string canonical_path = blaze_util::MakeCanonical(path.c_str());
if (canonical_path.empty()) {
// MakeCanonical returns an empty string when it fails. We ignore this
// failure since blazerc paths may point to invalid locations.
} else if (canonical_paths.find(canonical_path) == canonical_paths.end()) {
result.push_back(path);
canonical_paths.insert(canonical_path);
}
}
return result;
}
} // namespace internal

// Parses the arguments provided in args using the workspace path and the
// current working directory (cwd) and stores the results.
blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
const vector<string>& args,
const string& workspace,
Expand All @@ -307,7 +327,6 @@ blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
initialized_ = true;

args_ = args;
// Check if there is a blazerc related option given
std::unique_ptr<CommandLine> cmdLine = SplitCommandLine(args, error);
if (cmdLine == nullptr) {
return blaze_exit_code::BAD_ARGV;
Expand All @@ -324,7 +343,9 @@ blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
use_master_blazerc = false;
}

// Parse depot and user blazerc files.
// Use the workspace path, the current working directory, the path to the
// blaze binary and the startup args to determine the list of possible
// paths to the rc files. This list may contain duplicates.
vector<string> candidate_blazerc_paths;
if (use_master_blazerc) {
workspace_layout_->FindCandidateBlazercPaths(
Expand All @@ -340,15 +361,12 @@ blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
}
candidate_blazerc_paths.push_back(user_blazerc_path);

// Throw away missing files, dedupe candidate blazerc paths, and parse the
// blazercs, all while preserving order. Duplicates can arise if e.g. the
// binary's path *is* the depot path.
set<string> blazerc_paths;
for (const auto& candidate_blazerc_path : candidate_blazerc_paths) {
if (!candidate_blazerc_path.empty()
&& (blazerc_paths.insert(candidate_blazerc_path).second)) {
blazercs_.push_back(
new RcFile(candidate_blazerc_path, blazercs_.size()));
vector<string> deduped_blazerc_paths =
internal::DedupeBlazercPaths(candidate_blazerc_paths);

for (const auto& blazerc_path : deduped_blazerc_paths) {
if (!blazerc_path.empty()) {
blazercs_.push_back(new RcFile(blazerc_path, blazercs_.size()));
blaze_exit_code::ExitCode parse_exit_code =
blazercs_.back()->Parse(workspace, workspace_layout_, &blazercs_,
&rcoptions_, error);
Expand All @@ -364,15 +382,16 @@ blaze_exit_code::ExitCode OptionProcessor::ParseOptions(
return parse_startup_options_exit_code;
}

// Determine command
// Once we're done with startup options the next arg is the command.
if (startup_args_ + 1 >= args.size()) {
command_ = "";
return blaze_exit_code::SUCCESS;
}

command_ = args[startup_args_ + 1];

AddRcfileArgsAndOptions(cwd);

// The rest of the args are the command options.
for (unsigned int cmd_arg = startup_args_ + 2;
cmd_arg < args.size(); cmd_arg++) {
command_arguments_.push_back(args[cmd_arg]);
Expand Down
11 changes: 11 additions & 0 deletions src/main/cpp/option_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,25 @@ class OptionProcessor {
void AddRcfileArgsAndOptions(const std::string& cwd);
blaze_exit_code::ExitCode ParseStartupOptions(std::string* error);

// The list of parsed rc files, this field is initialized by ParseOptions.
std::vector<RcFile*> blazercs_;
std::map<std::string, std::vector<RcOption> > rcoptions_;
// The original args given by the user, this field is initialized by
// ParseOptions.
std::vector<std::string> args_;
// The index in args where the last startup option occurs, this field is
// initialized by ParseOptions.
unsigned int startup_args_;
// The command found in args, this field is initialized by ParseOptions.
std::string command_;
// The list of command options found in args, this field is initialized by
// ParseOptions.
std::vector<std::string> command_arguments_;
// Whether ParseOptions has been called.
bool initialized_;
const WorkspaceLayout* workspace_layout_;
// The startup options parsed from args, this field is initialized by
// ParseOptions.
std::unique_ptr<StartupOptions> parsed_startup_options_;
};

Expand Down

0 comments on commit b379f65

Please sign in to comment.