Skip to content

Commit

Permalink
[FEATURE] Adapt input/output file validator to read extensions from a…
Browse files Browse the repository at this point in the history
… file.
  • Loading branch information
rrahn committed Aug 14, 2019
1 parent 78932ba commit 661007e
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 40 deletions.
148 changes: 116 additions & 32 deletions include/seqan3/argument_parser/validators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <seqan3/core/detail/to_string.hpp>
#include <seqan3/core/type_traits/basic.hpp>
#include <seqan3/core/type_traits/pre.hpp>
#include <seqan3/io/detail/misc.hpp>
#include <seqan3/io/detail/safe_filesystem_entry.hpp>
#include <seqan3/range/container/concept.hpp>
#include <seqan3/range/view/drop.hpp>
Expand Down Expand Up @@ -236,12 +237,17 @@ value_list_validator(std::initializer_list<const char *>) -> value_list_validato

/*!\brief An abstract base class for the file and directory validators.
* \ingroup argument_parser
* \tparam file_t The type of the file to get the valid extensions for; `void` on default.
*
* \details
*
* This class provides a common interface for seqan3::input_file_validator and the seqan3::output_file_validator as
* well as the seqan3::input_directory_validator and seqan3::output_directory_validator.
*
* The type can be further specialised for the seqan3::input_file_validator and the seqan3::output_file_validator
* using the template argument to determine the valid extensions from the given file type.
*/
template <typename file_t = void>
class file_validator_base
{
public:
Expand All @@ -252,16 +258,47 @@ class file_validator_base
/*!\name Constructors, destructor and assignment
* \{
*/
file_validator_base() = default; //!< Defaulted.
/*!\brief Default constructor.
*
* \details
*
* If the class' template argument `file_t` names a valid seqan3 file type that contains a
* static member `valid_formats`, e.g. seqan3::sequence_input_file::valid_formats, then it generates the
* list of valid extensions from this file. Otherwise the extensions list is empty.
*/
//!\cond
template <typename _file_t = file_t>
requires std::Same<_file_t, void>
//!\endcond
file_validator_base()
{}

//!\cond
template <typename _file_t = file_t>
requires requires { typename _file_t::valid_formats; }

file_validator_base() : extensions{detail::valid_file_extensions<typename file_t::valid_formats>()}
{}
//!\endcond

file_validator_base(file_validator_base const &) = default; //!< Defaulted.
file_validator_base(file_validator_base &&) = default; //!< Defaulted.
file_validator_base & operator=(file_validator_base const &) = default; //!< Defaulted.
file_validator_base & operator=(file_validator_base &&) = default; //!< Defaulted.
virtual ~file_validator_base() = default; //!< Virtual destructor.

/*!\brief Constructs from a set of valid extensions.
/*!\brief Constructs from a given collection of valid extensions.
* \param[in] extensions The valid extensions to validate for.
*
* \details
*
* This constructor is only available if `file_t` does not name a valid seqan3 file type that contains a
* static member `valid_formats`.
*/
//!\cond
template <typename _file_t = file_t>
requires std::Same<_file_t, void>
//!\endcond
explicit file_validator_base(std::vector<std::string> extensions) : extensions{std::move(extensions)}
{}
//!\}
Expand Down Expand Up @@ -384,6 +421,7 @@ class file_validator_base
/*!\brief A validator that checks if a given path is a valid input file.
* \ingroup argument_parser
* \implements seqan3::Validator
* \tparam file_t The type of the file to get the valid extensions for; `void` on default.
*
* \details
*
Expand All @@ -394,30 +432,41 @@ class file_validator_base
*
* \include test/snippet/argument_parser/validators_input_file.cpp
*
* The valid extensions can also be obtained from a seqan3 formatted file type, e.g. seqan3::sequence_input_file, if
* it is given as template argument to this class. The following snippet demonstrates the different ways to instantiate
* the seqan3::output_file_validator.
*
* \include test/snippet/argument_parser/validators_input_file_ext_from_file.cpp
*
* \note The validator works on every type that can be implicitly converted to std::filesystem::path.
*/
class input_file_validator : public file_validator_base
template <typename file_t = void>
class input_file_validator : public file_validator_base<file_t>
{
public:
// Import from base class.
using file_validator_base::value_type;
using typename file_validator_base<file_t>::value_type;

/*!\name Constructors, destructor and assignment
* \{
*/
input_file_validator() = default; //!< Defaulted.
//!\copydoc seqan3::file_validator_base::file_validator_base()
input_file_validator() = default;
input_file_validator(input_file_validator const &) = default; //!< Defaulted.
input_file_validator(input_file_validator &&) = default; //!< Defaulted.
input_file_validator & operator=(input_file_validator const &) = default; //!< Defaulted.
input_file_validator & operator=(input_file_validator &&) = default; //!< Defaulted.
virtual ~input_file_validator() = default; //!< Virtual destructor.

//!\copydoc seqan3::file_validator_base::file_validator_base(std::vector<std::string>)
SEQAN3_DOXYGEN_ONLY(input_file_validator(std::vector<std::string> extensions){})

// Import base class constructor.
using file_validator_base::file_validator_base;
using file_validator_base<file_t>::file_validator_base;
//!\}

// Import the base::operator()
using file_validator_base::operator();
using file_validator_base<file_t>::operator();

/*!\brief Tests whether path is an existing regular file and is readable.
* \param file The input value to check.
Expand All @@ -432,10 +481,10 @@ class input_file_validator : public file_validator_base
throw parser_invalid_argument(detail::to_string("The file ", file, " does not exist!"));

// Check if file is regular and can be opened for reading.
validate_readability(file);
this->validate_readability(file);

// Check extension.
validate_filename(file);
this->validate_filename(file);
}
catch (std::filesystem::filesystem_error & ex)
{
Expand All @@ -450,15 +499,27 @@ class input_file_validator : public file_validator_base
//!\brief Returns a message that can be appended to the (positional) options help page info.
std::string get_help_page_message() const
{
return detail::to_string("Valid input file formats: ",
file_validator_base::extensions | std::view::join(std::string{", "}),
".");
return detail::to_string("Valid input file formats: [",
this->extensions | std::view::join(std::string{", "}),
"]");
}
};

/*!\name Type deduction guides
* \relates seqan3::input_file_validator
* \{
*/
//!\brief Default constructor deduces to default template argument.
input_file_validator() -> input_file_validator<>;

//!\brief Construction from extension collection deduces to the default template argument.
input_file_validator(std::vector<std::string>) -> input_file_validator<>;
//!\}

/*!\brief A validator that checks if a given path is a valid output file.
* \ingroup argument_parser
* \implements seqan3::Validator
* \tparam file_t The type of the file to get the valid extensions for; `void` on default.
*
* \details
*
Expand All @@ -469,30 +530,41 @@ class input_file_validator : public file_validator_base
*
* \include test/snippet/argument_parser/validators_output_file.cpp
*
* The valid extensions can also be obtained from a seqan3 formatted file type, e.g. seqan3::sequence_input_file, if
* it is given as template argument to this class. The following snippet demonstrates the different ways to instantiate
* the seqan3::output_file_validator.
*
* \include test/snippet/argument_parser/validators_output_file_ext_from_file.cpp
*
* \note The validator works on every type that can be implicitly converted to std::filesystem::path.
*/
class output_file_validator : public file_validator_base
template <typename file_t = void>
class output_file_validator : public file_validator_base<file_t>
{
public:
// Import from base class.
using file_validator_base::value_type;
using typename file_validator_base<file_t>::value_type;

/*!\name Constructors, destructor and assignment
* \{
*/
output_file_validator() = default; //!< Defaulted.
//!\copydoc seqan3::file_validator_base::file_validator_base()
output_file_validator() = default;
output_file_validator(output_file_validator const &) = default; //!< Defaulted.
output_file_validator(output_file_validator &&) = default; //!< Defaulted.
output_file_validator & operator=(output_file_validator const &) = default; //!< Defaulted.
output_file_validator & operator=(output_file_validator &&) = default; //!< Defaulted.
virtual ~output_file_validator() = default; //!< Virtual Destructor.

//!\copydoc seqan3::file_validator_base::file_validator_base(std::vector<std::string>)
SEQAN3_DOXYGEN_ONLY(output_file_validator(std::vector<std::string> extensions){})

// Import base constructor.
using file_validator_base::file_validator_base;
using file_validator_base<file_t>::file_validator_base;
//!\}

// Import the base::operator()
using file_validator_base::operator();
using file_validator_base<file_t>::operator();

/*!\brief Tests whether path is does not already exists and is writable.
* \param file The input value to check.
Expand All @@ -507,9 +579,9 @@ class output_file_validator : public file_validator_base
throw parser_invalid_argument(detail::to_string("The file ", file, " already exists!"));

// Check if file has any write permissions.
validate_writeability(file);
this->validate_writeability(file);

validate_filename(file);
this->validate_filename(file);
}
catch (std::filesystem::filesystem_error & ex)
{
Expand All @@ -524,11 +596,23 @@ class output_file_validator : public file_validator_base
//!\brief Returns a message that can be appended to the (positional) options help page info.
std::string get_help_page_message() const
{
return detail::to_string("Valid output file formats: ",
file_validator_base::extensions | std::view::join(std::string{", "}), ".");
return detail::to_string("Valid output file formats: [",
this->extensions | std::view::join(std::string{", "}),
"]");
}
};

/*!\name Type deduction guides
* \relates seqan3::output_file_validator
* \{
*/
//!\brief Default constructor deduces to default template argument.
output_file_validator() -> output_file_validator<>;

//!\brief Construction from extension collection deduces to the default template argument.
output_file_validator(std::vector<std::string>) -> output_file_validator<>;
//!\}

/*!\brief A validator that checks if a given path is a valid input directory.
* \ingroup argument_parser
* \implements seqan3::Validator
Expand All @@ -543,11 +627,11 @@ class output_file_validator : public file_validator_base
*
* \note The validator works on every type that can be implicitly converted to std::filesystem::path.
*/
class input_directory_validator : public file_validator_base
class input_directory_validator : public file_validator_base<>
{
public:
// Import from base class.
using file_validator_base::value_type;
using typename file_validator_base<>::value_type;

/*!\name Constructors, destructor and assignment
* \{
Expand All @@ -560,11 +644,11 @@ class input_directory_validator : public file_validator_base
virtual ~input_directory_validator() = default; //!< Virtual Destructor.

// Import base constructor.
using file_validator_base::file_validator_base;
using file_validator_base<>::file_validator_base;
//!\}

// Import the base::operator()
using file_validator_base::operator();
using file_validator_base<>::operator();

/*!\brief Tests whether path is an existing directory and is readable.
* \param dir The input value to check.
Expand All @@ -582,7 +666,7 @@ class input_directory_validator : public file_validator_base
throw parser_invalid_argument(detail::to_string("The path ", dir, " is not a directory!"));

// Check if directory has any read permissions.
validate_readability(dir);
this->validate_readability(dir);
}
catch (std::filesystem::filesystem_error & ex)
{
Expand Down Expand Up @@ -615,11 +699,11 @@ class input_directory_validator : public file_validator_base
*
* \note The validator works on every type that can be implicitly converted to std::filesystem::path.
*/
class output_directory_validator : public file_validator_base
class output_directory_validator : public file_validator_base<>
{
public:
// Imported from base class.
using file_validator_base::value_type;
using typename file_validator_base<>::value_type;

/*!\name Constructors, destructor and assignment
* \{
Expand All @@ -632,11 +716,11 @@ class output_directory_validator : public file_validator_base
virtual ~output_directory_validator() = default; //!< Virtual Destructor.

// Import base constructor.
using file_validator_base::file_validator_base;
using file_validator_base<>::file_validator_base;
//!\}

// Import the base::operator().
using file_validator_base::operator();
using file_validator_base<>::operator();

/*!\brief Tests whether path is writable.
* \param dir The input value to check.
Expand All @@ -658,12 +742,12 @@ class output_directory_validator : public file_validator_base
if (!dir_exists)
{
detail::safe_filesystem_entry dir_guard{dir};
validate_writeability(dir / "dummy.txt");
this->validate_writeability(dir / "dummy.txt");
dir_guard.remove_all();
}
else
{
validate_writeability(dir / "dummy.txt");
this->validate_writeability(dir / "dummy.txt");
}
}
catch (std::filesystem::filesystem_error & ex)
Expand Down
1 change: 0 additions & 1 deletion include/seqan3/io/detail/magic_header.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include <array>
#include <tuple>

#include <seqan3/core/type_traits/basic.hpp>
#include <seqan3/core/type_traits/template_inspection.hpp>
#include <seqan3/core/platform.hpp>
#include <seqan3/core/type_list/type_list.hpp>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <seqan3/argument_parser/validators.hpp>
#include <seqan3/io/sequence_file/input.hpp>
#include <seqan3/core/debug_stream.hpp>

int main(int argc, const char ** argv)
{

// Default constructed validator has an empty extension list.
seqan3::input_file_validator validator1{};
seqan3::debug_stream << validator1.get_help_page_message() << "\n";

// Specify your own extensions for the input file.
seqan3::input_file_validator validator2{std::vector{std::string{"exe"}, std::string{"fasta"}}};
seqan3::debug_stream << validator2.get_help_page_message() << "\n";

// Give as a template argument the seqan3 file type to get all valid extensions for this file.
seqan3::input_file_validator<seqan3::sequence_file_input<>> validator3{};
seqan3::debug_stream << validator3.get_help_page_message() << "\n";

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <seqan3/argument_parser/validators.hpp>
#include <seqan3/io/sequence_file/output.hpp>
#include <seqan3/core/debug_stream.hpp>

int main(int argc, const char ** argv)
{

// Default constructed validator has an empty extension list.
seqan3::output_file_validator validator1{};
seqan3::debug_stream << validator1.get_help_page_message() << "\n";

// Specify your own extensions for the output file.
seqan3::output_file_validator validator2{std::vector{std::string{"exe"}, std::string{"fasta"}}};
seqan3::debug_stream << validator2.get_help_page_message() << "\n";

// Give as a template argument the seqan3 file type to get all valid extensions for this file.
seqan3::output_file_validator<seqan3::sequence_file_output<>> validator3{};
seqan3::debug_stream << validator3.get_help_page_message() << "\n";

return 0;
}
Loading

0 comments on commit 661007e

Please sign in to comment.