diff options
author | Matthias Maennich <maennich@google.com> | 2021-11-08 22:26:27 +0000 |
---|---|---|
committer | Matthias Maennich <maennich@google.com> | 2021-11-09 18:48:32 +0000 |
commit | abd3c5f79420405903661c8c86656aca5b6a2b96 (patch) | |
tree | 3fe565f22097b2c83669b5101db5f6000fc721ec /interceptor/interceptor.cc | |
parent | c55b76cbf334d18096d4224ca0193e0d66de00d0 (diff) | |
download | build-tools-abd3c5f79420405903661c8c86656aca5b6a2b96.tar.gz |
Interceptor: relativate execution based on `cwd`
`ROOT_DIR` - if set, otherwise assume `cwd` - is assumed to be the
directory all execution is done relatively to. Hence, when rewriting
commands, do it with that directory as a base.
The interceptor wrapper is determining the INTERCEPTOR_root_dir based on
either ROOT_DIR or falls back to `cwd`.
Bug: 205577427
Signed-off-by: Matthias Maennich <maennich@google.com>
Change-Id: Ifef91ce7ae446d1a6cea7a744f36d0ff27cb4b3e
Diffstat (limited to 'interceptor/interceptor.cc')
-rw-r--r-- | interceptor/interceptor.cc | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/interceptor/interceptor.cc b/interceptor/interceptor.cc index 71f67a2..98b8e5e 100644 --- a/interceptor/interceptor.cc +++ b/interceptor/interceptor.cc @@ -35,6 +35,7 @@ namespace fs = std::filesystem; // Options passed via environment variables from the interceptor starter constexpr static auto ENV_command_log = "INTERCEPTOR_command_log"; +constexpr static auto ENV_root_dir = "INTERCEPTOR_root_dir"; // UTILITY function declarations @@ -121,6 +122,45 @@ std::string Command::repr() const { os << "}"; return os.str(); } + +void Command::make_relative() { + // determine the ROOT_DIR + std::string root_dir; + if (auto it = env().find(ENV_root_dir); it != env().cend()) { + root_dir = it->second; + if (root_dir[root_dir.size() - 1] != '/') root_dir += '/'; + } else { + return; + } + + // determine the relative path to ROOT_DIR from the current working dir + std::string rel_root = fs::relative(root_dir); + if (rel_root[rel_root.size() - 1] != '/') rel_root += '/'; + if (rel_root == "./") rel_root = ""; + + // TODO: This is generally bad as this means we can't make anything relative. + // This happens if the out dir is outside of the root. + if (rel_root.find(root_dir) != std::string::npos) { + return; + } + + cwd_ = fs::relative(cwd_, root_dir); + + // replacement functor + const auto replace_all = [&](auto& str) { + auto pos = std::string::npos; + while ((pos = str.find(root_dir)) != std::string::npos) { + str.replace(pos, root_dir.length(), rel_root); + } + }; + + if (!args_.has_value()) args(); + + // now go and replace everything + replace_all(program_); + std::for_each(args_->begin(), args_->end(), replace_all); +} + } // namespace interceptor /// UTILITY FUNCTIONS @@ -133,9 +173,15 @@ static void process_command(const char* filename, char* const argv[], char* cons return; } - // Ok, we can handle that one, let's log it. + // Ok, we can handle that one, let's transform it. interceptor::Command command(filename, argv, envp); + + // rewrite all command line arguments (including the program itself) to use + // paths relative to ROOT_DIR. This is essential for reproducible builds and + // furthermore necessary to produce cache hits in RBE. + command.make_relative(); + log(command, ""); // pass down the transformed command to execve |