From: Joel Rosdahl Date: Sun, 5 Jul 2020 20:07:06 +0000 (+0200) Subject: Add “--extract-result” option X-Git-Tag: v4.0~346 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d97b6dde86a9706f08d140f8d73f0b821569323f;p=thirdparty%2Fccache.git Add “--extract-result” option “ccache --extract-result” extracts data stored in a result file to the current working directory. --- diff --git a/doc/MANUAL.adoc b/doc/MANUAL.adoc index 11fb5691d..e5811f7bd 100644 --- a/doc/MANUAL.adoc +++ b/doc/MANUAL.adoc @@ -159,13 +159,19 @@ Options for scripting or debugging *`--dump-manifest`* _PATH_:: - Dump manifest file at _PATH_ in text format. This is only useful when - debugging ccache and its behavior. + Dump manifest file at _PATH_ in text format to standard output. This is + only useful when debugging ccache and its behavior. *`--dump-result`* _PATH_:: - Dump result file at _PATH_ in text format. This is only useful when - debugging ccache and its behavior. + Dump result file at _PATH_ in text format to standard output. This is only + useful when debugging ccache and its behavior. + +*`--extract-result`* _PATH_:: + + Extract data stored in the result file at _PATH_. The data will be written + to *ccache-result.** files in to the current working directory. This is + only useful when debugging ccache and its behavior. *`-k`* _KEY_, *`--get-config`* _KEY_:: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e50e1355..29838355e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,7 @@ set( ProgressBar.cpp Result.cpp ResultDumper.cpp + ResultExtractor.cpp ResultRetriever.cpp SignalHandler.cpp Stat.cpp diff --git a/src/Result.cpp b/src/Result.cpp index 6661084df..375e911e2 100644 --- a/src/Result.cpp +++ b/src/Result.cpp @@ -140,6 +140,7 @@ namespace Result { const uint8_t k_magic[4] = {'c', 'C', 'r', 'S'}; const uint8_t k_version = 1; +const char* const k_unknown_file_type = ""; const char* file_type_to_string(FileType type) @@ -167,7 +168,7 @@ file_type_to_string(FileType type) return ".dwo"; } - return ""; + return k_unknown_file_type; } Result::Reader::Reader(const std::string& result_path) diff --git a/src/Result.hpp b/src/Result.hpp index 8918996b6..ff80174b1 100644 --- a/src/Result.hpp +++ b/src/Result.hpp @@ -34,6 +34,7 @@ namespace Result { extern const uint8_t k_magic[4]; extern const uint8_t k_version; +extern const char* const k_unknown_file_type; using UnderlyingFileTypeInt = uint8_t; enum class FileType : UnderlyingFileTypeInt { diff --git a/src/ResultExtractor.cpp b/src/ResultExtractor.cpp new file mode 100644 index 000000000..4409b0644 --- /dev/null +++ b/src/ResultExtractor.cpp @@ -0,0 +1,84 @@ +// Copyright (C) 2020 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#include "ResultExtractor.hpp" + +#include "Context.hpp" +#include "logging.hpp" + +#include "third_party/nonstd/string_view.hpp" + +using string_view = nonstd::string_view; + +ResultExtractor::ResultExtractor(const std::string& directory) + : m_directory(directory) +{ +} + +void +ResultExtractor::on_header(CacheEntryReader& /*cache_entry_reader*/) +{ +} + +void +ResultExtractor::on_entry_start(uint32_t /*entry_number*/, + Result::FileType file_type, + uint64_t /*file_len*/, + nonstd::optional raw_file) +{ + std::string suffix = Result::file_type_to_string(file_type); + if (suffix == Result::k_unknown_file_type) { + suffix = fmt::format(".type_{}", file_type); + } else if (suffix[0] == '<') { + suffix[0] = '.'; + suffix.resize(suffix.length() - 1); + } + + m_dest_path = fmt::format("{}/ccache-result{}", m_directory, suffix); + + if (!raw_file) { + m_dest_fd = Fd( + open(m_dest_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)); + if (!m_dest_fd) { + throw Error(fmt::format( + "Failed to open {} for writing: {}", m_dest_path, strerror(errno))); + } + + } else if (!copy_file(raw_file->c_str(), m_dest_path.c_str(), false)) { + throw Error(fmt::format( + "Failed to copy {} to {}: {}", *raw_file, m_dest_path, strerror(errno))); + } +} + +void +ResultExtractor::on_entry_data(const uint8_t* data, size_t size) +{ + assert(m_dest_fd); + + if (!write_fd(*m_dest_fd, data, size)) { + throw Error(fmt::format("Failed to write to {}", m_dest_path)); + } +} + +void +ResultExtractor::on_entry_end() +{ + if (m_dest_fd) { + m_dest_fd.close(); + } +} diff --git a/src/ResultExtractor.hpp b/src/ResultExtractor.hpp new file mode 100644 index 000000000..14b6871ea --- /dev/null +++ b/src/ResultExtractor.hpp @@ -0,0 +1,46 @@ +// Copyright (C) 2020 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#pragma once + +#include "system.hpp" + +#include "Fd.hpp" +#include "Result.hpp" + +class Context; + +// This class extracts the parts of a result entry to a directory. +class ResultExtractor : public Result::Reader::Consumer +{ +public: + ResultExtractor(const std::string& directory); + + virtual void on_header(CacheEntryReader& cache_entry_reader); + virtual void on_entry_start(uint32_t entry_number, + Result::FileType file_type, + uint64_t file_len, + nonstd::optional raw_file); + virtual void on_entry_data(const uint8_t* data, size_t size); + virtual void on_entry_end(); + +private: + const std::string m_directory; + Fd m_dest_fd; + std::string m_dest_path; +}; diff --git a/src/ResultRetriever.hpp b/src/ResultRetriever.hpp index 48cb84b44..a5baba328 100644 --- a/src/ResultRetriever.hpp +++ b/src/ResultRetriever.hpp @@ -25,7 +25,7 @@ class Context; -// This class retrieves an result entry to the local file system. +// This class retrieves a result entry to the local file system. class ResultRetriever : public Result::Reader::Consumer { public: diff --git a/src/ccache.cpp b/src/ccache.cpp index 685dbc468..6d2a821ae 100644 --- a/src/ccache.cpp +++ b/src/ccache.cpp @@ -30,6 +30,7 @@ #include "ProgressBar.hpp" #include "Result.hpp" #include "ResultDumper.hpp" +#include "ResultExtractor.hpp" #include "ResultRetriever.hpp" #include "SignalHandler.hpp" #include "StdMakeUnique.hpp" @@ -108,6 +109,8 @@ Common options: Options for scripting or debugging: --dump-manifest PATH dump manifest file at PATH in text format --dump-result PATH dump result file at PATH in text format + --extract-result PATH extract data stored in result file at PATH to the + current working directory -k, --get-config KEY print the value of configuration key KEY --hash-file PATH print the hash (160 bit BLAKE3) of the file at PATH @@ -2189,6 +2192,7 @@ handle_main_options(int argc, const char* const* argv) enum longopts { DUMP_MANIFEST, DUMP_RESULT, + EXTRACT_RESULT, HASH_FILE, PRINT_STATS, }; @@ -2197,6 +2201,7 @@ handle_main_options(int argc, const char* const* argv) {"clear", no_argument, nullptr, 'C'}, {"dump-manifest", required_argument, nullptr, DUMP_MANIFEST}, {"dump-result", required_argument, nullptr, DUMP_RESULT}, + {"extract-result", required_argument, nullptr, EXTRACT_RESULT}, {"get-config", required_argument, nullptr, 'k'}, {"hash-file", required_argument, nullptr, HASH_FILE}, {"help", no_argument, nullptr, 'h'}, @@ -2236,6 +2241,16 @@ handle_main_options(int argc, const char* const* argv) return error ? EXIT_FAILURE : EXIT_SUCCESS; } + case EXTRACT_RESULT: { + ResultExtractor result_extractor("."); + Result::Reader result_reader(optarg); + auto error = result_reader.read(result_extractor); + if (error) { + fmt::print(stderr, "Error: {}\n", *error); + } + return error ? EXIT_FAILURE : EXIT_SUCCESS; + } + case HASH_FILE: { struct hash* hash = hash_init(); if (str_eq(optarg, "-")) {