Loading...
Searching...
No Matches
validators.hpp
Go to the documentation of this file.
// --------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2023, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2023, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/raptor/blob/main/LICENSE.md
// --------------------------------------------------------------------------------------------------
#pragma once
#include <sharg/parser.hpp>
#include <seqan3/io/sequence_file/input.hpp>
#include <raptor/strong_types.hpp>
namespace raptor::detail
{
static inline std::vector<std::string> sequence_extensions{
seqan3::detail::valid_file_extensions<typename seqan3::sequence_file_input<>::valid_formats>()};
static inline std::vector<std::string> compression_extensions{[]()
{
std::vector<std::string> result;
#ifdef SEQAN3_HAS_BZIP2
result.push_back("bz2");
#endif
#ifdef SEQAN3_HAS_ZLIB
result.push_back("gz");
result.push_back("bgzf");
#endif
return result;
}()}; // GCOVR_EXCL_LINE
static inline std::vector<std::string> combined_extensions{
[]()
{
if (compression_extensions.empty())
return sequence_extensions; // GCOVR_EXCL_LINE
std::vector<std::string> result;
for (auto && sequence_extension : sequence_extensions)
{
result.push_back(sequence_extension);
for (auto && compression_extension : compression_extensions)
result.push_back(sequence_extension + std::string{'.'} + compression_extension);
}
return result;
}()};
} // namespace raptor::detail
namespace raptor
{
struct power_of_two_validator
{
using option_value_type = size_t;
void operator()(option_value_type const & val) const
{
if (!std::has_single_bit(val))
throw sharg::validation_error{"The value must be a power of two."};
}
static std::string get_help_page_message()
{
return "Value must be a power of two.";
}
};
class positive_integer_validator
{
public:
using option_value_type = size_t;
positive_integer_validator() = default;
positive_integer_validator(positive_integer_validator const &) = default;
positive_integer_validator & operator=(positive_integer_validator const &) = default;
positive_integer_validator(positive_integer_validator &&) = default;
positive_integer_validator & operator=(positive_integer_validator &&) = default;
~positive_integer_validator() = default;
explicit positive_integer_validator(bool const is_zero_positive_) : is_zero_positive{is_zero_positive_}
{}
void operator()(option_value_type const & val) const
{
if (!is_zero_positive && !val)
throw sharg::validation_error{"The value must be a positive integer."};
}
std::string get_help_page_message() const
{
if (is_zero_positive)
return "Value must be a positive integer or 0.";
else
return "Value must be a positive integer.";
}
private:
bool is_zero_positive{false};
};
class size_validator
{
public:
using option_value_type = std::string;
size_validator() = default;
size_validator(size_validator const &) = default;
size_validator & operator=(size_validator const &) = default;
size_validator(size_validator &&) = default;
size_validator & operator=(size_validator &&) = default;
~size_validator() = default;
explicit size_validator(std::string const & pattern) : expression{pattern}
{}
void operator()(option_value_type const & cmp) const
{
if (!std::regex_match(cmp, expression))
throw sharg::validation_error{
seqan3::detail::to_string("Value ",
cmp,
" must be an integer followed by [k,m,g,t] (case insensitive).")};
}
template <std::ranges::forward_range range_type>
requires std::convertible_to<std::ranges::range_value_t<range_type>, option_value_type const &>
void operator()(range_type const & v) const
{
std::for_each(v.begin(),
v.end(),
[&](auto cmp)
{
(*this)(cmp);
});
}
std::string get_help_page_message() const
{
return "Must be an integer followed by [k,m,g,t] (case insensitive).";
}
private:
std::regex expression;
};
class bin_validator
{
public:
using option_value_type = std::vector<std::vector<std::string>>;
bin_validator() = default;
bin_validator(bin_validator const &) = default;
bin_validator & operator=(bin_validator const &) = default;
bin_validator(bin_validator &&) = default;
bin_validator & operator=(bin_validator &&) = default;
~bin_validator() = default;
void operator()(option_value_type const & values) const
{
if (values.empty())
throw sharg::validation_error{"The list of input files cannot be empty."};
bool const is_minimiser_input = std::filesystem::path{values[0][0]}.extension() == ".minimiser";
for (std::vector<std::string> const & vector_of_paths : values)
{
for (std::string const & value : vector_of_paths)
{
std::filesystem::path const file_path{value};
if (is_minimiser_input && (file_path.extension() != ".minimiser"))
throw sharg::validation_error{"You cannot mix sequence and minimiser files as input."};
if (std::filesystem::file_size(file_path) == 0u)
throw sharg::validation_error{"The file " + value + " is empty."};
if (is_minimiser_input)
minimiser_file_validator(file_path);
else
sequence_file_validator(file_path);
}
}
}
std::string get_help_page_message() const
{
return seqan3::detail::to_string("The file must contain at least one file path per line, with multiple paths "
"being separated by a whitespace. Each line in the file corresponds to one "
"bin. Valid extensions for the paths in the file are [minimiser] when "
" using preprocessed input from \\fBraptor prepare\\fP, and ",
raptor::detail::sequence_extensions,
#if defined(SEQAN3_HAS_BZIP2) || defined(SEQAN3_HAS_ZLIB)
", possibly followed by ",
raptor::detail::compression_extensions,
#endif
". ");
}
private:
sharg::input_file_validator minimiser_file_validator{{"minimiser"}};
public:
sharg::input_file_validator sequence_file_validator{raptor::detail::combined_extensions};
};
class output_directory_validator
{
public:
using option_value_type = std::string;
output_directory_validator() = default;
output_directory_validator(output_directory_validator const &) = default;
output_directory_validator & operator=(output_directory_validator const &) = default;
output_directory_validator(output_directory_validator &&) = default;
output_directory_validator & operator=(output_directory_validator &&) = default;
~output_directory_validator() = default;
void operator()(option_value_type const & value) const
{
std::filesystem::path const out_dir{value};
std::error_code ec{};
std::filesystem::create_directories(out_dir, ec);
if (ec)
// GCOVR_EXCL_START
throw sharg::validation_error{
sharg::detail::to_string("Failed to create directory\"", out_dir.c_str(), "\": ", ec.message())};
// GCOVR_EXCL_STOP
validator(out_dir);
}
std::string get_help_page_message() const
{
return "A valid path for the output directory.";
}
private:
sharg::output_directory_validator validator{};
};
class output_file_validator
{
public:
using option_value_type = std::string;
output_file_validator() = default;
output_file_validator(output_file_validator const &) = default;
output_file_validator & operator=(output_file_validator const &) = default;
output_file_validator(output_file_validator &&) = default;
output_file_validator & operator=(output_file_validator &&) = default;
~output_file_validator() = default;
void operator()(option_value_type const & value) const
{
std::filesystem::path const out_path{value};
std::filesystem::path const out_dir{out_path.parent_path()};
if (!out_dir.empty())
{
// GCOVR_EXCL_START
std::error_code ec{};
std::filesystem::create_directories(out_dir, ec);
if (ec)
throw sharg::validation_error{
sharg::detail::to_string("Failed to create directory \"", out_dir.c_str(), "\": ", ec.message())};
// GCOVR_EXCL_STOP
}
validator(out_path);
}
std::string get_help_page_message() const
{
return "A valid path for the output file. Write permissions must be granted.";
}
private:
sharg::output_file_validator validator{sharg::output_file_open_options::open_or_create};
};
class sequence_file_validator : public sharg::input_file_validator
{
private:
using base_t = sharg::input_file_validator;
public:
using base_t::base_t;
std::string get_help_page_message() const
{
return seqan3::detail::to_string(
"The input file must exist and read permissions must be granted. Valid file extensions are ",
raptor::detail::sequence_extensions,
#if defined(SEQAN3_HAS_BZIP2) || defined(SEQAN3_HAS_ZLIB)
", possibly followed by ",
raptor::detail::compression_extensions,
#endif
". ");
}
};
} // namespace raptor
std::regex
std::string
raptor::sequence_file_validator
Definition validators.hpp:288
std::filesystem::create_directories
T create_directories(T... args)
std::vector::empty
T empty(T... args)
std::error_code
std::filesystem::path::extension
T extension(T... args)
std::filesystem::file_size
T file_size(T... args)
std::for_each
T for_each(T... args)
std::error_code::message
T message(T... args)
std::filesystem::path::c_str
T c_str(T... args)
std::filesystem::path::parent_path
T parent_path(T... args)
std::filesystem::path
std::vector::push_back
T push_back(T... args)
std::regex_match
T regex_match(T... args)
strong_types.hpp
Provides raptor::window.
raptor::power_of_two_validator
Definition validators.hpp:61
std::vector