mirror of
https://github.com/mhx/dwarfs.git
synced 2025-08-03 17:56:12 -04:00
feat(dwarfsck): select detail features by name
This commit is contained in:
parent
248a16c7bb
commit
4f95d66d57
@ -937,6 +937,7 @@ if(WITH_TESTS)
|
||||
integral_value_parser_test
|
||||
lazy_value_test
|
||||
metadata_requirements_test
|
||||
options_test
|
||||
pcm_sample_transformer_test
|
||||
pcmaudio_categorizer_test
|
||||
speedometer_test
|
||||
|
@ -18,9 +18,9 @@ with a non-zero exit code.
|
||||
Path to the filesystem image.
|
||||
|
||||
- `-d`, `--detail=`*value*:
|
||||
Level of filesystem information detail. The default is 2. Higher values
|
||||
mean more output. Values larger than 6 will currently not provide any
|
||||
further detail.
|
||||
Level of filesystem information detail. This can be a numeric level
|
||||
between 0 and 6, or a comma-separated list of feature names. The
|
||||
default corresponds to a level of 2.
|
||||
|
||||
- `-q`, `--quiet`:
|
||||
Don't produce any output unless there is an error.
|
||||
|
@ -110,7 +110,12 @@ class fsinfo_features {
|
||||
|
||||
static constexpr fsinfo_features all() { return fsinfo_features().set_all(); }
|
||||
|
||||
static int max_level();
|
||||
static fsinfo_features for_level(int level);
|
||||
static fsinfo_features parse(std::string_view str);
|
||||
|
||||
std::string to_string() const;
|
||||
std::vector<std::string_view> to_string_views() const;
|
||||
|
||||
constexpr bool has(fsinfo_feature f) const {
|
||||
return features_ & (1 << static_cast<size_t>(f));
|
||||
@ -155,10 +160,11 @@ class fsinfo_features {
|
||||
using feature_type = uint64_t;
|
||||
static constexpr size_t max_feature_bits{
|
||||
std::numeric_limits<feature_type>::digits};
|
||||
static constexpr size_t num_feature_bits{
|
||||
static_cast<size_t>(fsinfo_feature::num_fsinfo_feature_bits)};
|
||||
static_assert(num_feature_bits <= max_feature_bits);
|
||||
|
||||
feature_type features_{0};
|
||||
static_assert(static_cast<size_t>(fsinfo_feature::num_fsinfo_feature_bits) <=
|
||||
max_feature_bits);
|
||||
};
|
||||
|
||||
struct fsinfo_options {
|
||||
|
@ -19,11 +19,15 @@
|
||||
* along with dwarfs. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <range/v3/view/split.hpp>
|
||||
|
||||
#include <dwarfs/error.h>
|
||||
#include <dwarfs/options.h>
|
||||
|
||||
@ -46,9 +50,36 @@ constexpr std::array level_features{
|
||||
{fsinfo_feature::directory_tree, fsinfo_feature::frozen_layout}),
|
||||
/* 5 */ fsinfo_features({fsinfo_feature::chunk_details}),
|
||||
/* 6 */ fsinfo_features({fsinfo_feature::metadata_full_dump}),
|
||||
/* 7 */ fsinfo_features({}),
|
||||
};
|
||||
|
||||
constexpr std::array<std::pair<fsinfo_feature, std::string_view>,
|
||||
static_cast<int>(fsinfo_feature::num_fsinfo_feature_bits)>
|
||||
fsinfo_feature_names{{
|
||||
#define FSINFO_FEATURE_PAIR_(f) {fsinfo_feature::f, #f}
|
||||
FSINFO_FEATURE_PAIR_(version),
|
||||
FSINFO_FEATURE_PAIR_(history),
|
||||
FSINFO_FEATURE_PAIR_(metadata_summary),
|
||||
FSINFO_FEATURE_PAIR_(metadata_details),
|
||||
FSINFO_FEATURE_PAIR_(metadata_full_dump),
|
||||
FSINFO_FEATURE_PAIR_(frozen_analysis),
|
||||
FSINFO_FEATURE_PAIR_(frozen_layout),
|
||||
FSINFO_FEATURE_PAIR_(directory_tree),
|
||||
FSINFO_FEATURE_PAIR_(section_details),
|
||||
FSINFO_FEATURE_PAIR_(chunk_details),
|
||||
#undef FSINFO_FEATURE_PAIR_
|
||||
}};
|
||||
|
||||
constexpr bool fsinfo_feature_names_in_order() {
|
||||
for (size_t i = 0; i < fsinfo_feature_names.size(); ++i) {
|
||||
if (fsinfo_feature_names[i].first != static_cast<fsinfo_feature>(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static_assert(fsinfo_feature_names_in_order());
|
||||
|
||||
} // namespace
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, file_order_mode mode) {
|
||||
@ -97,6 +128,10 @@ mlock_mode parse_mlock_mode(std::string_view mode) {
|
||||
DWARFS_THROW(runtime_error, fmt::format("invalid lock mode: {}", mode));
|
||||
}
|
||||
|
||||
int fsinfo_features::max_level() {
|
||||
return static_cast<int>(level_features.size()) - 1;
|
||||
}
|
||||
|
||||
fsinfo_features fsinfo_features::for_level(int level) {
|
||||
fsinfo_features features;
|
||||
|
||||
@ -109,4 +144,51 @@ fsinfo_features fsinfo_features::for_level(int level) {
|
||||
return features;
|
||||
}
|
||||
|
||||
fsinfo_features fsinfo_features::parse(std::string_view features) {
|
||||
fsinfo_features result;
|
||||
|
||||
for (auto const& f : features | ranges::views::split(',')) {
|
||||
// TODO: This should be much simpler with C++23
|
||||
std::string_view fsv(&*f.begin(), ranges::distance(f));
|
||||
auto const it =
|
||||
std::find_if(fsinfo_feature_names.begin(), fsinfo_feature_names.end(),
|
||||
[&fsv](auto const& p) { return fsv == p.second; });
|
||||
|
||||
if (it == fsinfo_feature_names.end()) {
|
||||
DWARFS_THROW(runtime_error, fmt::format("invalid feature: \"{}\"", fsv));
|
||||
}
|
||||
|
||||
result |= it->first;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string fsinfo_features::to_string() const {
|
||||
std::string result;
|
||||
|
||||
for (size_t bit = 0; bit < num_feature_bits; ++bit) {
|
||||
if (has(static_cast<fsinfo_feature>(bit))) {
|
||||
if (!result.empty()) {
|
||||
result += ',';
|
||||
}
|
||||
result += fsinfo_feature_names[bit].second;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string_view> fsinfo_features::to_string_views() const {
|
||||
std::vector<std::string_view> result;
|
||||
|
||||
for (size_t bit = 0; bit < num_feature_bits; ++bit) {
|
||||
if (has(static_cast<fsinfo_feature>(bit))) {
|
||||
result.push_back(fsinfo_feature_names[bit].second);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace dwarfs
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <folly/portability/Unistd.h>
|
||||
|
||||
#include <dwarfs/checksum.h>
|
||||
#include <dwarfs/conv.h>
|
||||
#include <dwarfs/error.h>
|
||||
#include <dwarfs/file_access.h>
|
||||
#include <dwarfs/filesystem_v2.h>
|
||||
@ -161,12 +162,16 @@ int dwarfsck_main(int argc, sys_char** argv, iolayer const& iol) {
|
||||
auto algo_list = checksum::available_algorithms();
|
||||
auto checksum_desc = fmt::format("print checksums for all files ({})",
|
||||
fmt::join(algo_list, ", "));
|
||||
auto detail_desc = fmt::format(
|
||||
"detail level (0-{}, or feature list: {})", fsinfo_features::max_level(),
|
||||
fmt::join(fsinfo_features::all().to_string_views(), ", "));
|
||||
auto const detail_default{fsinfo_features::for_level(2).to_string()};
|
||||
|
||||
sys_string input, export_metadata;
|
||||
std::string image_offset, checksum_algo;
|
||||
logger_options logopts;
|
||||
size_t num_workers;
|
||||
int detail;
|
||||
std::string detail;
|
||||
bool quiet{false};
|
||||
bool verbose{false};
|
||||
bool output_json{false};
|
||||
@ -182,8 +187,8 @@ int dwarfsck_main(int argc, sys_char** argv, iolayer const& iol) {
|
||||
po_sys_value<sys_string>(&input),
|
||||
"input filesystem")
|
||||
("detail,d",
|
||||
po::value<int>(&detail)->default_value(2),
|
||||
"detail level")
|
||||
po::value<std::string>(&detail)->default_value(detail_default.c_str()),
|
||||
detail_desc.c_str())
|
||||
("quiet,q",
|
||||
po::value<bool>(&quiet)->zero_tokens(),
|
||||
"don't print anything unless an error occurs")
|
||||
@ -327,7 +332,11 @@ int dwarfsck_main(int argc, sys_char** argv, iolayer const& iol) {
|
||||
|
||||
opts.block_access = no_check ? block_access_level::no_verify
|
||||
: block_access_level::unrestricted;
|
||||
opts.features = fsinfo_features::for_level(detail);
|
||||
|
||||
auto numeric_detail = tryTo<int>(detail);
|
||||
opts.features = numeric_detail.has_value()
|
||||
? fsinfo_features::for_level(*numeric_detail)
|
||||
: fsinfo_features::parse(detail);
|
||||
|
||||
if (output_json) {
|
||||
iol.out << fs.info_as_json(opts) << "\n";
|
||||
|
62
test/options_test.cpp
Normal file
62
test/options_test.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/**
|
||||
* \author Marcus Holland-Moritz (github@mhxnet.de)
|
||||
* \copyright Copyright (c) Marcus Holland-Moritz
|
||||
*
|
||||
* This file is part of dwarfs.
|
||||
*
|
||||
* dwarfs 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.
|
||||
*
|
||||
* dwarfs 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 dwarfs. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <dwarfs/options.h>
|
||||
|
||||
using namespace dwarfs;
|
||||
|
||||
TEST(options, fsinfo_features) {
|
||||
fsinfo_features ff;
|
||||
|
||||
EXPECT_EQ(ff.to_string(), "");
|
||||
|
||||
EXPECT_NO_THROW(ff |= fsinfo_features::parse("frozen_layout,history"));
|
||||
|
||||
EXPECT_TRUE(ff.has(fsinfo_feature::history));
|
||||
EXPECT_TRUE(ff & fsinfo_feature::frozen_layout);
|
||||
|
||||
EXPECT_FALSE(ff.has(fsinfo_feature::frozen_analysis));
|
||||
EXPECT_FALSE(ff & fsinfo_feature::version);
|
||||
|
||||
EXPECT_EQ(ff.to_string(), "history,frozen_layout");
|
||||
|
||||
ff.clear(fsinfo_feature::history);
|
||||
|
||||
EXPECT_FALSE(ff & fsinfo_feature::history);
|
||||
EXPECT_TRUE(ff & fsinfo_feature::frozen_layout);
|
||||
EXPECT_EQ(ff.to_string(), "frozen_layout");
|
||||
|
||||
ff.reset();
|
||||
|
||||
EXPECT_FALSE(ff & fsinfo_feature::frozen_layout);
|
||||
EXPECT_EQ(ff.to_string(), "");
|
||||
|
||||
EXPECT_THAT([]() { fsinfo_features::parse("history,whatever"); },
|
||||
testing::ThrowsMessage<runtime_error>(
|
||||
testing::HasSubstr("invalid feature: \"whatever\"")));
|
||||
|
||||
EXPECT_THAT([]() { fsinfo_features::parse("frozen_layout,history,x"); },
|
||||
testing::ThrowsMessage<runtime_error>(
|
||||
testing::HasSubstr("invalid feature: \"x\"")));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user