Print the checksum (128 bit XXH3) of the file at _PATH_ (`-` for standard
input).
-*--dump-manifest* _PATH_::
-
- Dump manifest file at _PATH_ (`-` for standard input) in text format to
- standard output. This is only useful when debugging ccache and its behavior.
-
-*--dump-result* _PATH_::
-
- Dump result file at _PATH_ (`-` for standard input) 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_ (`-` for standard input).
The data will be written to `ccache-result.*` files in to the current
- working directory. This is only useful when debugging ccache and its
+ working directory. This option is only useful when debugging ccache and its
behavior.
*-k* _KEY_, *--get-config* _KEY_::
Print the hash (160 bit BLAKE3) of the file at _PATH_ (`-` for standard
input). This is only useful when debugging ccache and its behavior.
+*--inspect* _PATH_::
+
+ Print the content of a result or manifest file at _PATH_ (`-` for standard
+ input) to standard output in human-readable format. File content embedded in
+ a result file will however not be printed; use `--extract-result` to extract
+ the file content. This option is only useful when debugging ccache and its
+ behavior.
+
*--print-stats*::
Print statistics counter IDs and corresponding values in machine-parsable
Logging.cpp
ProgressBar.cpp
Result.cpp
- ResultDumper.cpp
ResultExtractor.cpp
+ ResultInspector.cpp
ResultRetriever.cpp
SignalHandler.cpp
Stat.cpp
-// Copyright (C) 2019-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2019-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
return *this;
}
-Result::Reader::Reader(const std::string& result_path)
- : m_result_path(result_path)
+Result::Reader::Reader(core::CacheEntryReader& cache_entry_reader,
+ const std::string& result_path)
+ : m_reader(cache_entry_reader),
+ m_result_path(result_path)
{
}
-optional<std::string>
-Result::Reader::read(Consumer& consumer)
-{
- LOG("Reading result {}", m_result_path);
-
- try {
- if (read_result(consumer)) {
- return nullopt;
- } else {
- return "No such result file";
- }
- } catch (const core::Error& e) {
- return e.what();
- }
-}
-
-bool
-Reader::read_result(Consumer& consumer)
+void
+Reader::read(Consumer& consumer)
{
- FILE* file_stream;
- File file;
- if (m_result_path == "-") {
- file_stream = stdin;
- } else {
- file = File(m_result_path, "rb");
- if (!file) {
- // Cache miss.
- return false;
- }
- file_stream = file.get();
+ if (m_reader.header().entry_type != core::CacheEntryType::result) {
+ throw core::Error("Unexpected cache entry type: {}",
+ to_string(m_reader.header().entry_type));
}
- core::FileReader file_reader(file_stream);
- core::CacheEntryReader cache_entry_reader(file_reader);
-
- const auto result_format_version = cache_entry_reader.read_int<uint8_t>();
+ const auto result_format_version = m_reader.read_int<uint8_t>();
if (result_format_version != k_result_format_version) {
throw core::Error("Unknown result format version: {}",
result_format_version);
}
- consumer.on_header(cache_entry_reader, result_format_version);
-
- const auto n_entries = cache_entry_reader.read_int<uint8_t>();
+ const auto n_entries = m_reader.read_int<uint8_t>();
uint32_t i;
for (i = 0; i < n_entries; ++i) {
- read_entry(cache_entry_reader, i, consumer);
+ read_entry(i, consumer);
}
if (i != n_entries) {
throw core::Error("Too few entries (read {}, expected {})", i, n_entries);
}
- cache_entry_reader.finalize();
- return true;
+ m_reader.finalize();
}
void
-Reader::read_entry(core::CacheEntryReader& cache_entry_reader,
- uint32_t entry_number,
- Reader::Consumer& consumer)
+Reader::read_entry(uint32_t entry_number, Reader::Consumer& consumer)
{
- const auto marker = cache_entry_reader.read_int<uint8_t>();
+ const auto marker = m_reader.read_int<uint8_t>();
switch (marker) {
case k_embedded_file_marker:
throw core::Error("Unknown entry type: {}", marker);
}
- const auto type = cache_entry_reader.read_int<UnderlyingFileTypeInt>();
+ const auto type = m_reader.read_int<UnderlyingFileTypeInt>();
const auto file_type = FileType(type);
- const auto file_len = cache_entry_reader.read_int<uint64_t>();
+ const auto file_len = m_reader.read_int<uint64_t>();
if (marker == k_embedded_file_marker) {
consumer.on_entry_start(entry_number, file_type, file_len, nullopt);
size_t remain = file_len;
while (remain > 0) {
size_t n = std::min(remain, sizeof(buf));
- cache_entry_reader.read(buf, n);
+ m_reader.read(buf, n);
consumer.on_entry_data(buf, n);
remain -= n;
}
} else {
ASSERT(marker == k_raw_file_marker);
- auto raw_path = get_raw_file_path(m_result_path, entry_number);
- auto st = Stat::stat(raw_path, Stat::OnError::throw_error);
- if (st.size() != file_len) {
- throw core::Error(
- "Bad file size of {} (actual {} bytes, expected {} bytes)",
- raw_path,
- st.size(),
- file_len);
+ std::string raw_path;
+ if (m_result_path != "-") {
+ raw_path = get_raw_file_path(m_result_path, entry_number);
+ auto st = Stat::stat(raw_path, Stat::OnError::throw_error);
+ if (st.size() != file_len) {
+ throw core::Error(
+ "Bad file size of {} (actual {} bytes, expected {} bytes)",
+ raw_path,
+ st.size(),
+ file_len);
+ }
}
consumer.on_entry_start(entry_number, file_type, file_len, raw_path);
-// Copyright (C) 2019-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2019-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
#pragma once
+#include <core/Reader.hpp>
+
#include "third_party/nonstd/expected.hpp"
#include "third_party/nonstd/optional.hpp"
class Reader
{
public:
- Reader(const std::string& result_path);
+ Reader(core::CacheEntryReader& cache_entry_reader,
+ const std::string& result_path);
class Consumer
{
public:
virtual ~Consumer() = default;
- virtual void on_header(core::CacheEntryReader& cache_entry_reader,
- uint8_t result_format_version) = 0;
virtual void on_entry_start(uint32_t entry_number,
FileType file_type,
uint64_t file_len,
virtual void on_entry_end() = 0;
};
- // Returns error message on error, otherwise nonstd::nullopt.
- nonstd::optional<std::string> read(Consumer& consumer);
+ // Throws core::Error on error.
+ void read(Consumer& consumer);
private:
+ core::CacheEntryReader& m_reader;
const std::string m_result_path;
- bool read_result(Consumer& consumer);
- void read_entry(core::CacheEntryReader& cache_entry_reader,
- uint32_t entry_number,
- Reader::Consumer& consumer);
+ void read_entry(uint32_t entry_number, Reader::Consumer& consumer);
};
// This class knows how to write a result cache entry.
{
}
-void
-ResultExtractor::on_header(core::CacheEntryReader& /*cache_entry_reader*/,
- const uint8_t /*result_format_version*/)
-{
-}
-
void
ResultExtractor::on_entry_start(uint32_t /*entry_number*/,
Result::FileType file_type,
throw core::Error(
"Failed to open {} for writing: {}", m_dest_path, strerror(errno));
}
+ } else if (raw_file->empty()) {
+ PRINT_RAW(stderr,
+ "Note: Can't extract raw file since reading from stdin\n");
} else {
try {
Util::copy_file(*raw_file, m_dest_path, false);
-// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
public:
ResultExtractor(const std::string& directory);
- void on_header(core::CacheEntryReader& cache_entry_reader,
- uint8_t result_format_version) override;
void on_entry_start(uint32_t entry_number,
Result::FileType file_type,
uint64_t file_len,
-// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#include "ResultDumper.hpp"
+#include "ResultInspector.hpp"
#include "Context.hpp"
#include "Logging.hpp"
#include "fmtmacros.hpp"
-#include <core/CacheEntryReader.hpp>
-
using nonstd::optional;
-ResultDumper::ResultDumper(FILE* stream) : m_stream(stream)
-{
-}
-
-void
-ResultDumper::on_header(core::CacheEntryReader& cache_entry_reader,
- const uint8_t result_format_version)
+ResultInspector::ResultInspector(FILE* stream) : m_stream(stream)
{
- cache_entry_reader.header().dump(m_stream);
- PRINT(m_stream, "Result format version: {}\n", result_format_version);
}
void
-ResultDumper::on_entry_start(uint32_t entry_number,
- Result::FileType file_type,
- uint64_t file_len,
- optional<std::string> raw_file)
+ResultInspector::on_entry_start(uint32_t entry_number,
+ Result::FileType file_type,
+ uint64_t file_len,
+ optional<std::string> raw_file)
{
PRINT(m_stream,
"{} file #{}: {} ({} bytes)\n",
}
void
-ResultDumper::on_entry_data(const uint8_t* /*data*/, size_t /*size*/)
+ResultInspector::on_entry_data(const uint8_t* /*data*/, size_t /*size*/)
{
}
void
-ResultDumper::on_entry_end()
+ResultInspector::on_entry_end()
{
}
-// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
#include <cstdint>
#include <cstdio>
-// This class dumps information about the result entry to `stream`.
-class ResultDumper : public Result::Reader::Consumer
+// This class writes information about the result entry to `stream`.
+class ResultInspector : public Result::Reader::Consumer
{
public:
- ResultDumper(FILE* stream);
+ ResultInspector(FILE* stream);
- void on_header(core::CacheEntryReader& cache_entry_reader,
- uint8_t result_format_version) override;
void on_entry_start(uint32_t entry_number,
Result::FileType file_type,
uint64_t file_len,
-// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
{
}
-void
-ResultRetriever::on_header(core::CacheEntryReader& /*cache_entry_reader*/,
- const uint8_t /*result_format_version*/)
-{
-}
-
void
ResultRetriever::on_entry_start(uint32_t entry_number,
FileType file_type,
-// Copyright (C) 2020-2021 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
public:
ResultRetriever(Context& ctx, bool rewrite_dependency_target);
- void on_header(core::CacheEntryReader& cache_entry_reader,
- uint8_t result_format_version) override;
void on_entry_start(uint32_t entry_number,
Result::FileType file_type,
uint64_t file_len,
return false;
}
- Result::Reader result_reader(*result_path);
+ File file(*result_path, "rb");
+ core::FileReader file_reader(file.get());
+ core::CacheEntryReader cache_entry_reader(file_reader);
+ Result::Reader result_reader(cache_entry_reader, *result_path);
ResultRetriever result_retriever(
ctx, should_rewrite_dependency_target(ctx.args_info));
- auto error = result_reader.read(result_retriever);
- if (error) {
- LOG("Failed to get result from cache: {}", *error);
+ try {
+ result_reader.read(result_retriever);
+ } catch (core::Error& e) {
+ LOG("Failed to get result from cache: {}", e.what());
return false;
}
}
void
-CacheEntryHeader::dump(FILE* const stream) const
+CacheEntryHeader::inspect(FILE* const stream) const
{
PRINT(stream, "Magic: {:04x}\n", magic);
PRINT(stream, "Entry format version: {}\n", entry_format_version);
-// Copyright (C) 2021 Joel Rosdahl and other contributors
+// Copyright (C) 2021-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
uint64_t payload_size() const;
void set_entry_size_from_payload_size(uint64_t payload_size);
- void dump(FILE* stream) const;
+ void inspect(FILE* stream) const;
private:
size_t non_payload_size() const;
-// Copyright (C) 2021 Joel Rosdahl and other contributors
+// Copyright (C) 2021-2022 Joel Rosdahl and other contributors
//
// See doc/AUTHORS.adoc for a complete list of contributors.
//
#include <Hash.hpp>
#include <InodeCache.hpp>
#include <ProgressBar.hpp>
-#include <ResultDumper.hpp>
+#include <Result.hpp>
#include <ResultExtractor.hpp>
+#include <ResultInspector.hpp>
#include <ccache.hpp>
#include <core/CacheEntryReader.hpp>
#include <core/FileReader.hpp>
Options for scripting or debugging:
--checksum-file PATH print the checksum (128 bit XXH3) of the file at
PATH
- --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
+ --extract-result PATH extract file 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
+ --inspect PATH print result/manifest file at PATH in
+ human-readable format
--print-stats print statistics counter IDs and corresponding
values in machine-parsable format
PRINT(stdout, "({}) {} = {}\n", origin, key, value);
}
+static int
+inspect_path(const std::string& path)
+{
+ File file = path == "-" ? File(stdin) : File(path, "rb");
+ if (!file) {
+ PRINT(stderr, "Error: Failed to open \"{}\"", path);
+ return EXIT_FAILURE;
+ }
+ core::FileReader file_reader(file.get());
+ core::CacheEntryReader cache_entry_reader(file_reader);
+
+ const auto& header = cache_entry_reader.header();
+ header.inspect(stdout);
+
+ switch (header.entry_type) {
+ case core::CacheEntryType::manifest: {
+ core::Manifest manifest;
+ manifest.read(cache_entry_reader);
+ cache_entry_reader.finalize();
+ manifest.dump(stdout);
+ break;
+ }
+ case core::CacheEntryType::result:
+ Result::Reader result_reader(cache_entry_reader, path);
+ ResultInspector result_inspector(stdout);
+ result_reader.read(result_inspector);
+ break;
+ }
+
+ return EXIT_SUCCESS;
+}
+
static void
print_compression_statistics(const storage::primary::CompressionStatistics& cs)
{
EVICT_OLDER_THAN,
EXTRACT_RESULT,
HASH_FILE,
+ INSPECT,
PRINT_STATS,
SHOW_LOG_STATS,
TRIM_DIR,
{"clear", no_argument, nullptr, 'C'},
{"config-path", required_argument, nullptr, CONFIG_PATH},
{"dir", required_argument, nullptr, 'd'},
- {"directory", required_argument, nullptr, 'd'}, // backward compatibility
- {"dump-manifest", required_argument, nullptr, DUMP_MANIFEST},
- {"dump-result", required_argument, nullptr, DUMP_RESULT},
+ {"directory", required_argument, nullptr, 'd'}, // bwd compat
+ {"dump-manifest", required_argument, nullptr, DUMP_MANIFEST}, // bwd compat
+ {"dump-result", required_argument, nullptr, DUMP_RESULT}, // bwd compat
{"evict-namespace", required_argument, nullptr, EVICT_NAMESPACE},
{"evict-older-than", required_argument, nullptr, EVICT_OLDER_THAN},
{"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'},
+ {"inspect", required_argument, nullptr, INSPECT},
{"max-files", required_argument, nullptr, 'F'},
{"max-size", required_argument, nullptr, 'M'},
{"print-stats", no_argument, nullptr, PRINT_STATS},
break;
}
- case DUMP_MANIFEST: {
- File file(arg, "rb");
- if (!file) {
- throw Fatal("No such file: {}", arg);
- }
- core::FileReader file_reader(*file);
- core::CacheEntryReader reader(file_reader);
- core::Manifest manifest;
- manifest.read(reader);
- reader.finalize();
- manifest.dump(stdout);
- return 0;
- }
-
- case DUMP_RESULT: {
- ResultDumper result_dumper(stdout);
- Result::Reader result_reader(arg);
- auto error = result_reader.read(result_dumper);
- if (error) {
- PRINT(stderr, "Error: {}\n", *error);
- }
- return error ? EXIT_FAILURE : EXIT_SUCCESS;
- }
-
case EVICT_NAMESPACE: {
evict_namespace = arg;
break;
case EXTRACT_RESULT: {
ResultExtractor result_extractor(".");
- Result::Reader result_reader(arg);
- auto error = result_reader.read(result_extractor);
- if (error) {
- PRINT(stderr, "Error: {}\n", *error);
+ File file = arg == "-" ? File(stdin) : File(arg, "rb");
+ if (!file) {
+ PRINT(stderr, "Error: Failed to open \"{}\"", arg);
+ return EXIT_FAILURE;
}
- return error ? EXIT_FAILURE : EXIT_SUCCESS;
+ core::FileReader file_reader(file.get());
+ core::CacheEntryReader cache_entry_reader(file_reader);
+ Result::Reader result_reader(cache_entry_reader, arg);
+ result_reader.read(result_extractor);
+ return EXIT_SUCCESS;
}
case HASH_FILE: {
break;
}
+ case INSPECT:
+ case DUMP_MANIFEST: // Backward compatibility
+ case DUMP_RESULT: // Backward compatibility
+ return inspect_path(arg);
+
case PRINT_STATS: {
StatisticsCounters counters;
time_t last_updated;
$CCACHE_COMPILE -c test1.c
result_file=$(find $CCACHE_DIR -name '*R')
- if ! $CCACHE --dump-result $result_file | grep 'Compression type: zstd' >/dev/null 2>&1; then
+ if ! $CCACHE --inspect $result_file | grep 'Compression type: zstd' >/dev/null 2>&1; then
test_failed "Result file not uncompressed according to metadata"
fi
if [ $(file_size $result_file) -ge $(file_size test1.o) ]; then
manifest=`find $CCACHE_DIR -name '*M'`
if [ -n "$manifest" ]; then
- data="`$CCACHE --dump-manifest $manifest | egrep '/dev/(stdout|tty|sda|hda'`"
+ data="`$CCACHE --inspect $manifest | egrep '/dev/(stdout|tty|sda|hda'`"
if [ -n "$data" ]; then
test_failed "$manifest contained troublesome file(s): $data"
fi
fi
# -------------------------------------------------------------------------
- TEST "--dump-manifest"
+ TEST "--inspect"
$CCACHE_COMPILE test.c -c -o test.o
manifest=`find $CCACHE_DIR -name '*M'`
- $CCACHE --dump-manifest $manifest >manifest.dump
+ $CCACHE --inspect $manifest >manifest.dump
checksum_test1_h='b7273h0ksdehi0o4pitg5jeehal3i54ns'
checksum_test2_h='24f1315jch5tcndjbm6uejtu8q3lf9100'
grep "Hash: $checksum_test3_h" manifest.dump >/dev/null 2>&1; then
: OK
else
- test_failed "Unexpected output of --dump-manifest"
+ test_failed "Unexpected output of --inspect"
fi
# -------------------------------------------------------------------------
CCACHE_IGNOREHEADERS="subdir/ignore.h" $CCACHE_COMPILE -c ignore.c
manifest=`find $CCACHE_DIR -name '*M'`
- data="`$CCACHE --dump-manifest $manifest | grep subdir/ignore.h`"
+ data="`$CCACHE --inspect $manifest | grep subdir/ignore.h`"
if [ -n "$data" ]; then
test_failed "$manifest contained ignored header: $data"
fi
CCACHE_IGNOREHEADERS="subdir" $CCACHE_COMPILE -c ignore.c
manifest=`find $CCACHE_DIR -name '*M'`
- data="`$CCACHE --dump-manifest $manifest | grep subdir/ignore.h`"
+ data="`$CCACHE --inspect $manifest | grep subdir/ignore.h`"
if [ -n "$data" ]; then
test_failed "$manifest contained ignored header: $data"
fi
$CCACHE_COMPILE -c test.c
result_file=$(find $CCACHE_DIR -name '*R')
- if ! $CCACHE --dump-result $result_file | grep 'Compression type: none' >/dev/null 2>&1; then
+ if ! $CCACHE --inspect $result_file | grep 'Compression type: none' >/dev/null 2>&1; then
test_failed "Result file not uncompressed according to metadata"
fi
if [ $(file_size $result_file) -le $(file_size test.o) ]; then