12
12
13
13
#pragma once
14
14
15
- #include < regex>
15
+ #include < seqan3/std/algorithm>
16
+ #include < seqan3/std/concepts>
17
+ #include < seqan3/std/filesystem>
16
18
#include < fstream>
19
+ #include < seqan3/std/ranges>
20
+ #include < regex>
17
21
#include < sstream>
18
22
19
23
#include < seqan3/argument_parser/exceptions.hpp>
26
30
#include < seqan3/io/detail/safe_filesystem_entry.hpp>
27
31
#include < seqan3/range/container/concept.hpp>
28
32
#include < seqan3/range/views/join.hpp>
29
- #include < seqan3/std/algorithm>
30
- #include < seqan3/std/concepts>
31
- #include < seqan3/std/filesystem>
32
- #include < seqan3/std/ranges>
33
33
34
34
namespace seqan3
35
35
{
@@ -384,9 +384,8 @@ class file_validator_base
384
384
385
385
// Check if extension is available.
386
386
if (!path.has_extension ())
387
- throw validation_error{detail::to_string (" The given filename " , path.string (),
388
- " has no extension. Expected one of the following valid"
389
- " extensions:" , extensions, " !" )};
387
+ throw validation_error{detail::to_string (" The given filename " , path.string (), " has no extension. Expected"
388
+ " one of the following valid extensions:" , extensions, " !" )};
390
389
391
390
// Drop the dot.
392
391
std::string drop_less_ext = path.extension ().string ().substr (1 );
@@ -403,8 +402,8 @@ class file_validator_base
403
402
// Check if requested extension is present.
404
403
if (std::ranges::find_if (extensions, case_insensitive_equal_to) == extensions.end ())
405
404
{
406
- throw validation_error{detail::to_string (" Expected one of the following valid extensions: " ,
407
- extensions, " ! Got " , drop_less_ext, " instead!" )};
405
+ throw validation_error{detail::to_string (" Expected one of the following valid extensions: " , extensions,
406
+ " ! Got " , drop_less_ext, " instead!" )};
408
407
}
409
408
}
410
409
@@ -587,6 +586,15 @@ class input_file_validator : public file_validator_base
587
586
}
588
587
};
589
588
589
+ // !\brief Mode of an output file: Determines whether an existing file can be (silently) overwritten.
590
+ enum class output_file_open_options
591
+ {
592
+ // !\brief Allow to overwrite the output file
593
+ open_or_create,
594
+ // !\brief Forbid overwriting the output file
595
+ create_new
596
+ };
597
+
590
598
/* !\brief A validator that checks if a given path is a valid output file.
591
599
* \ingroup argument_parser
592
600
* \implements seqan3::validator
@@ -595,9 +603,13 @@ class input_file_validator : public file_validator_base
595
603
* \details
596
604
*
597
605
* On construction, the validator can receive a list (std::vector over std::string) of valid file extensions.
598
- * The class acts as a functor that throws a seqan3::validation_error exception whenever a given filename's
599
- * extension (sts::string) is not in the given list of valid file extensions, if the file already exist, or if the
600
- * parent path does not have the proper writer permissions.
606
+ * The class acts as a functor that throws a seqan3::validation_error exception whenever a given filename's extension
607
+ * (std::string) is not in the given list of valid file extensions, or if the parent path does not have the proper
608
+ * writer permissions.
609
+ * In addition, the validator receives a seqan3::output_file_open_options which allows you to specify what to do if your
610
+ * output file already exists. seqan3::output_file_open_options::create_new will throw a seqan3::validation_error
611
+ * exception if it already exists and seqan3::output_file_open_options::open_or_create will skip this check (that means
612
+ * you are allowed to overwrite the existing file).
601
613
*
602
614
* \include test/snippet/argument_parser/validators_output_file.cpp
603
615
*
@@ -613,7 +625,6 @@ template <typename file_t = void>
613
625
class output_file_validator : public file_validator_base
614
626
{
615
627
public:
616
-
617
628
static_assert (std::same_as<file_t , void > || detail::has_type_valid_formats<file_t >,
618
629
" Expected either a template type with a static member called valid_formats (a file type) or void." );
619
630
@@ -625,24 +636,24 @@ class output_file_validator : public file_validator_base
625
636
*/
626
637
627
638
// !\copydoc seqan3::input_file_validator::input_file_validator()
628
- output_file_validator ()
629
- {
630
- if constexpr (!std::same_as<file_t , void >)
631
- file_validator_base::extensions = detail::valid_file_extensions<typename file_t ::valid_formats>();
632
- }
633
-
634
- output_file_validator (output_file_validator const &) = default ; // !< Defaulted.
635
- output_file_validator (output_file_validator &&) = default ; // !< Defaulted.
636
- output_file_validator & operator =(output_file_validator const &) = default ; // !< Defaulted.
637
- output_file_validator & operator =(output_file_validator &&) = default ; // !< Defaulted.
638
- virtual ~output_file_validator () = default ; // !< Virtual Destructor.
639
+ output_file_validator () : output_file_validator{output_file_open_options::create_new}
640
+ {}
639
641
640
- // !\copydoc seqan3::input_file_validator::input_file_validator(std::vector<std::string>)
641
- explicit output_file_validator (std::vector<std::string> extensions)
642
- // !\cond
643
- requires std::same_as<file_t, void>
644
- // !\endcond
645
- : file_validator_base{}
642
+ output_file_validator (output_file_validator const &) = default ; // !< Defaulted.
643
+ output_file_validator (output_file_validator &&) = default ; // !< Defaulted.
644
+ output_file_validator & operator =(output_file_validator const &) = default ; // !< Defaulted.
645
+ output_file_validator & operator =(output_file_validator &&) = default ; // !< Defaulted.
646
+ virtual ~output_file_validator () = default ; // !< Virtual Destructor.
647
+
648
+ /* !\brief Constructs from a given overwrite mode and a list of valid extensions.
649
+ * \param[in] mode A seqan3::output_file_open_options indicating whether the validator throws if a file already
650
+ exists.
651
+ * \param[in] extensions The valid extensions to validate for. Defaults to
652
+ * seqan3::output_file_validator::default_extensions.
653
+ */
654
+ explicit output_file_validator (output_file_open_options const mode,
655
+ std::vector<std::string> extensions = default_extensions())
656
+ : file_validator_base{}, mode{mode}
646
657
{
647
658
file_validator_base::extensions = std::move (extensions);
648
659
}
@@ -651,6 +662,21 @@ class output_file_validator : public file_validator_base
651
662
using file_validator_base::file_validator_base;
652
663
// !\}
653
664
665
+ /* !\brief The default extensions of `file_t`.
666
+ * \returns A list of default extensions for `file_t`, will be empty if `file_t` is `void`.
667
+ *
668
+ * \details
669
+ *
670
+ * If `file_t` does name a valid seqan3 file type that contains a static member `valid_formats` returns the
671
+ * extensions of that `file_t` type. Otherwise returns an empty list.
672
+ */
673
+ static std::vector<std::string> default_extensions ()
674
+ {
675
+ if constexpr (!std::same_as<file_t , void >)
676
+ return detail::valid_file_extensions<typename file_t ::valid_formats>();
677
+ return {};
678
+ }
679
+
654
680
// Import the base::operator()
655
681
using file_validator_base::operator ();
656
682
@@ -663,7 +689,7 @@ class output_file_validator : public file_validator_base
663
689
{
664
690
try
665
691
{
666
- if (std::filesystem::exists (file))
692
+ if ((mode == output_file_open_options::create_new) && std::filesystem::exists (file))
667
693
throw validation_error{detail::to_string (" The file " , file, " already exists!" )};
668
694
669
695
// Check if file has any write permissions.
@@ -684,9 +710,16 @@ class output_file_validator : public file_validator_base
684
710
// !\brief Returns a message that can be appended to the (positional) options help page info.
685
711
std::string get_help_page_message () const
686
712
{
687
- return " The output file must not exist already and write permissions must be granted." +
688
- valid_extensions_help_page_message ();
713
+ if (mode == output_file_open_options::open_or_create)
714
+ return " Write permissions must be granted." + valid_extensions_help_page_message ();
715
+ else // mode == create_new
716
+ return " The output file must not exist already and write permissions must be granted." +
717
+ valid_extensions_help_page_message ();
689
718
}
719
+
720
+ private:
721
+ // !\brief Stores the current mode of whether it is valid to overwrite the output file.
722
+ output_file_open_options mode{output_file_open_options::create_new};
690
723
};
691
724
692
725
/* !\brief A validator that checks if a given path is a valid input directory.
0 commit comments