Commit 4ca2f7c6 authored by GILLES Sebastien's avatar GILLES Sebastien

#1480 Adding a new Directory class (and the appropriate unit test).

parent f1aa6de6
......@@ -525,6 +525,9 @@
BE3221911B4686C100F27D6C /* FElt.hxx in Headers */ = {isa = PBXBuildFile; fileRef = BE32218E1B4686C100F27D6C /* FElt.hxx */; };
BE32927D1A44702C009F0BE2 /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE32927A1A44702C009F0BE2 /* Exception.cpp */; };
BE32927E1A44702C009F0BE2 /* Exception.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BE32927B1A44702C009F0BE2 /* Exception.hpp */; };
BE35030A22F2E96700D09A4D /* Directory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE35030722F2E96700D09A4D /* Directory.cpp */; };
BE35030B22F2E96700D09A4D /* Directory.hxx in Headers */ = {isa = PBXBuildFile; fileRef = BE35030822F2E96700D09A4D /* Directory.hxx */; };
BE35030C22F2E96700D09A4D /* Directory.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BE35030922F2E96700D09A4D /* Directory.hpp */; };
BE353B9A22E7527100A06A8F /* Extract.hxx in Headers */ = {isa = PBXBuildFile; fileRef = BE353B9722E7527100A06A8F /* Extract.hxx */; };
BE353B9B22E7527100A06A8F /* Extract.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BE353B9822E7527100A06A8F /* Extract.hpp */; };
BE353B9F22E7539E00A06A8F /* Enum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE353B9C22E7539E00A06A8F /* Enum.cpp */; };
......@@ -3443,6 +3446,12 @@
BE32927A1A44702C009F0BE2 /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Exception.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
BE32927B1A44702C009F0BE2 /* Exception.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Exception.hpp; sourceTree = "<group>"; };
BE32FE221EC259420052F4AD /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README; path = RivlinCube/README; sourceTree = "<group>"; };
BE35030722F2E96700D09A4D /* Directory.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Directory.cpp; sourceTree = "<group>"; };
BE35030822F2E96700D09A4D /* Directory.hxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Directory.hxx; sourceTree = "<group>"; };
BE35030922F2E96700D09A4D /* Directory.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Directory.hpp; sourceTree = "<group>"; };
BE35030F22F30E6E00D09A4D /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
BE35031022F30E8300D09A4D /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
BE35031122F30FAA00D09A4D /* test.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = test.cpp; sourceTree = "<group>"; };
BE353B9722E7527100A06A8F /* Extract.hxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Extract.hxx; sourceTree = "<group>"; };
BE353B9822E7527100A06A8F /* Extract.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Extract.hpp; sourceTree = "<group>"; };
BE353B9C22E7539E00A06A8F /* Enum.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Enum.cpp; sourceTree = "<group>"; };
......@@ -6643,6 +6652,7 @@
isa = PBXGroup;
children = (
BE8B5FA72077D67400DC005E /* CMakeLists.txt */,
BE35030D22F30E2000D09A4D /* Filesystem */,
BE8B5F962077B21E00DC005E /* Environment */,
BE7E68842069554D00AA2FB3 /* TupleHasType */,
BEDE169B204EEB0F00DEFE08 /* LuaOptionFile */,
......@@ -6860,6 +6870,24 @@
name = "Recovered References";
sourceTree = "<group>";
};
BE35030D22F30E2000D09A4D /* Filesystem */ = {
isa = PBXGroup;
children = (
BE35030F22F30E6E00D09A4D /* CMakeLists.txt */,
BE35030E22F30E2D00D09A4D /* Directory */,
);
path = Filesystem;
sourceTree = "<group>";
};
BE35030E22F30E2D00D09A4D /* Directory */ = {
isa = PBXGroup;
children = (
BE35031022F30E8300D09A4D /* CMakeLists.txt */,
BE35031122F30FAA00D09A4D /* test.cpp */,
);
path = Directory;
sourceTree = "<group>";
};
BE353BA922E77F0700A06A8F /* PrintContainer */ = {
isa = PBXGroup;
children = (
......@@ -9810,6 +9838,9 @@
BEB991A118F41AC2009ACA4C /* File.hpp */,
BEB991A218F41AC2009ACA4C /* Folder.cpp */,
BEB991A318F41AC2009ACA4C /* Folder.hpp */,
BE35030722F2E96700D09A4D /* Directory.cpp */,
BE35030922F2E96700D09A4D /* Directory.hpp */,
BE35030822F2E96700D09A4D /* Directory.hxx */,
);
path = Filesystem;
sourceTree = "<group>";
......@@ -11523,6 +11554,7 @@
BEDE16A6204F365600DEFE08 /* LuaOptionFile.hpp in Headers */,
BE3FE9CB22C3D0D70093E95A /* LuaUtilityFunctions.hpp in Headers */,
BEC157F21A249C3D007D20EB /* Numeric.hpp in Headers */,
BE35030B22F2E96700D09A4D /* Directory.hxx in Headers */,
132BD2751C72136D008DDEE7 /* Solver.hxx in Headers */,
BE353BA122E7539E00A06A8F /* Enum.hpp in Headers */,
BE6E4EE31B2ABE8B0049BB2D /* AccessGhostContent.hxx in Headers */,
......@@ -11567,6 +11599,7 @@
BE3D12C11D9B1FFB00F900F5 /* KspConvergenceReason.hxx in Headers */,
BE168EA41CC96DA00090AC88 /* Tetrahedron4.hxx in Headers */,
BE41A8CF1A24AA46004E4312 /* Mpi.hxx in Headers */,
BE35030C22F2E96700D09A4D /* Directory.hpp in Headers */,
BE76F26A1D7D609E0061B50E /* GlobalVectorTemporary.hxx in Headers */,
BE90E1CE1A2492AA00CCAFDE /* PetscSnes.hpp in Headers */,
BE3D12C31D9B1FFB00F900F5 /* SnesConvergenceReason.hpp in Headers */,
......@@ -12982,6 +13015,7 @@
BE90E1AF1A24929A00CCAFDE /* Vector.cpp in Sources */,
BE110EA31E11514200D2D2C8 /* VectorHelper.cpp in Sources */,
BE90E1711A24926E00CCAFDE /* String.cpp in Sources */,
BE35030A22F2E96700D09A4D /* Directory.cpp in Sources */,
BEDEB9281C3C073100B1C71B /* Umfpack.cpp in Sources */,
BECEF92B22DF5D5E00D0DDE7 /* Now.cpp in Sources */,
BE8ADFAC1F05668100DB6762 /* BaseMatrix.cpp in Sources */,
......@@ -14,4 +14,5 @@ add_test(MpiGather
--
${MOREFEM_ROOT}
${MOREFEM_TEST_OUTPUT_DIR})
set_tests_properties(MpiGather PROPERTIES TIMEOUT 3)
......@@ -5,6 +5,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/LuaOptionFile/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/TypeName/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/Now/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/PrintContainer/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/Filesystem/CMakeLists.txt)
# Needs to be incorporated (or dropped) - see #1272
# include(${CMAKE_CURRENT_LIST_DIR}/InputData/CMakeLists.txt)
......
include(${CMAKE_CURRENT_LIST_DIR}/Directory/CMakeLists.txt)
add_executable(MoReFEMTestDirectory
${CMAKE_CURRENT_LIST_DIR}/test.cpp
)
target_link_libraries(MoReFEMTestDirectory
${MOREFEM_TEST_TOOLS}
)
add_test(TestDirectory
MoReFEMTestDirectory
--
${MOREFEM_ROOT}
${MOREFEM_TEST_OUTPUT_DIR})
add_test(TestDirectory-mpi
${OPEN_MPI_INCL_DIR}/../bin/mpirun
--oversubscribe
-np 4
MoReFEMTestDirectory
--
${MOREFEM_ROOT}
${MOREFEM_TEST_OUTPUT_DIR})
set_tests_properties(TestDirectory PROPERTIES TIMEOUT 5)
set_tests_properties(TestDirectory-mpi PROPERTIES TIMEOUT 5)
/*!
// \file
//
//
// Created by Sebastien Gilles <sebastien.gilles@inria.fr> on the Mon, 26 Mar 2018 18:46:03 +0200
// Copyright (c) Inria. All rights reserved.
//
*/
#include <fstream>
#define BOOST_TEST_MODULE utilities_directory
#include "ThirdParty/IncludeWithoutWarning/Boost/Test.hpp"
#include "Utilities/Filesystem/Directory.hpp"
#include "Utilities/Filesystem/File.hpp"
#include "Utilities/Environment/Environment.hpp"
#include "Test/Tools/Fixture/Mpi.hpp"
#include "Test/Tools/Fixture/Environment.hpp"
using namespace MoReFEM;
namespace // anonymous
{
struct fixture
: public TestNS::FixtureNS::Mpi,
public TestNS::FixtureNS::Environment
{ };
enum class stdin_case { yes, no };
template<stdin_case CaseT>
void SetStdin(std::ifstream& in, const std::string& directory_test);
} // namespace anonymous
PRAGMA_DIAGNOSTIC(push)
# ifdef __clang__
PRAGMA_DIAGNOSTIC(ignored "-Wdisabled-macro-expansion")
# endif // __clang__
BOOST_FIXTURE_TEST_CASE(overwrite, fixture)
{
decltype(auto) environment = Utilities::Environment::CreateOrGetInstance(__FILE__, __LINE__);
decltype(auto) test_dir = environment.GetEnvironmentVariable("MOREFEM_TEST_OUTPUT_DIR", __FILE__, __LINE__);
decltype(auto) mpi = GetMpi();
FilesystemNS::Directory overwrite(mpi,
test_dir + "/directory_test",
FilesystemNS::if_already_exist::overwrite,
__FILE__, __LINE__);
BOOST_CHECK(FilesystemNS::Folder::DoExist(overwrite));
FilesystemNS::Directory overwrite_once_again(mpi,
test_dir + "/directory_test",
FilesystemNS::if_already_exist::overwrite,
__FILE__, __LINE__);
}
BOOST_FIXTURE_TEST_CASE(read_case, fixture) // 'read' can't be used here hence the _case.
{
decltype(auto) environment = Utilities::Environment::CreateOrGetInstance(__FILE__, __LINE__);
decltype(auto) test_dir = environment.GetEnvironmentVariable("MOREFEM_TEST_OUTPUT_DIR", __FILE__, __LINE__);
decltype(auto) mpi = GetMpi();
const std::string directory_test = test_dir + "/directory_test";
BOOST_CHECK(FilesystemNS::Folder::DoExist(directory_test));
FilesystemNS::Directory read(mpi,
directory_test,
FilesystemNS::if_already_exist::ignore,
__FILE__, __LINE__);
BOOST_CHECK_EQUAL(read.GetPath(), directory_test + "/Rank_" + std::to_string(mpi.GetRank<int>()) + "/");
}
BOOST_FIXTURE_TEST_CASE(quit, fixture)
{
decltype(auto) environment = Utilities::Environment::CreateOrGetInstance(__FILE__, __LINE__);
decltype(auto) test_dir = environment.GetEnvironmentVariable("MOREFEM_TEST_OUTPUT_DIR", __FILE__, __LINE__);
decltype(auto) mpi = GetMpi();
const std::string directory_test = test_dir + "/directory_test";
BOOST_CHECK(FilesystemNS::Folder::DoExist(directory_test));
BOOST_CHECK_THROW(FilesystemNS::Directory read(mpi,
directory_test,
FilesystemNS::if_already_exist::quit,
__FILE__, __LINE__),
ExceptionNS::GracefulExit);
}
BOOST_FIXTURE_TEST_CASE(ask_yes, fixture)
{
decltype(auto) environment = Utilities::Environment::CreateOrGetInstance(__FILE__, __LINE__);
decltype(auto) test_dir = environment.GetEnvironmentVariable("MOREFEM_TEST_OUTPUT_DIR", __FILE__, __LINE__);
decltype(auto) mpi = GetMpi();
const std::string directory_test = test_dir + "/directory_test";
std::ifstream in;
SetStdin<stdin_case::yes>(in, directory_test);
FilesystemNS::Directory ask_yes(mpi,
directory_test,
FilesystemNS::if_already_exist::ask,
__FILE__, __LINE__);
}
BOOST_FIXTURE_TEST_CASE(ask_no, fixture)
{
decltype(auto) environment = Utilities::Environment::CreateOrGetInstance(__FILE__, __LINE__);
decltype(auto) test_dir = environment.GetEnvironmentVariable("MOREFEM_TEST_OUTPUT_DIR", __FILE__, __LINE__);
decltype(auto) mpi = GetMpi();
const std::string directory_test = test_dir + "/directory_test";
std::ifstream in;
SetStdin<stdin_case::no>(in, directory_test);
BOOST_CHECK_THROW(FilesystemNS::Directory ask_no(mpi,
directory_test,
FilesystemNS::if_already_exist::ask,
__FILE__, __LINE__),
ExceptionNS::GracefulExit);
}
// When the directory already exists ONLY for one of the non root rank...
BOOST_FIXTURE_TEST_CASE(ask_on_rank, fixture)
{
decltype(auto) mpi = GetMpi();
if (mpi.Nprocessor<int>() > 1)
{
decltype(auto) environment = Utilities::Environment::CreateOrGetInstance(__FILE__, __LINE__);
decltype(auto) test_dir = environment.GetEnvironmentVariable("MOREFEM_TEST_OUTPUT_DIR", __FILE__, __LINE__);
const std::string directory_test = test_dir + "/directory_test/asymmetric/";
if (mpi.IsRootProcessor())
{
std::string rank_2_dir = directory_test + "Rank_2";
if (!FilesystemNS::Folder::DoExist(rank_2_dir))
FilesystemNS::Folder::Create(rank_2_dir, __FILE__, __LINE__);
}
mpi.Barrier();
std::ifstream in;
SetStdin<stdin_case::yes>(in, directory_test);
FilesystemNS::Directory ask_yes(mpi,
directory_test,
FilesystemNS::if_already_exist::ask,
__FILE__, __LINE__);
}
}
PRAGMA_DIAGNOSTIC(pop)
namespace // anonymous
{
template<stdin_case CaseT>
void SetStdin(std::ifstream& in, const std::string& directory_test)
{
std::string stdin_file = directory_test + "/input_" + (CaseT == stdin_case::yes ? "yes" : "no") + ".txt";
std::ofstream out;
FilesystemNS::File::Create(out, stdin_file, __FILE__, __LINE__);
out << "w w e s f 4 515 s j" << std::endl;
if (CaseT == stdin_case::yes)
out << 'y';
else
out << 'n';
out.close();
in.close();
FilesystemNS::File::Read(in, stdin_file, __FILE__, __LINE__);
// See //https://stackoverflow.com/questions/10150468/how-to-redirect-cin-and-cout-to-files.
std::cin.rdbuf(in.rdbuf()); //redirect std::cin to in.txt!
}
}
//! \file
//
//
// Directory.cpp
// MoReFEM
//
// Created by sebastien on 01/08/2019.
//Copyright © 2019 Inria. All rights reserved.
//
#include <cassert>
#include <deque>
#include "Utilities/Containers/EnumClass.hpp"
#include "Utilities/Filesystem/Directory.hpp"
#include "Utilities/Exceptions/GracefulExit.hpp"
#include "Utilities/Containers/Print.hpp"
#include "ThirdParty/Wrappers/Mpi/Mpi.hpp"
namespace MoReFEM::FilesystemNS
{
namespace // anonymous
{
enum class ask_status
{
no_preexisting = 0,
remove_yes,
remove_no
};
ask_status AskCaseRootProcessor(const std::string& wildcard_path,
const std::vector<int>& result);
} // namespace anonymous
Directory::Directory(const Wrappers::Mpi& mpi,
const std::string& a_path,
if_already_exist if_already_exist_behaviour,
const char* invoking_file, int invoking_line)
: mpi_(mpi),
if_already_exist_behaviour_(if_already_exist_behaviour)
{
std::ostringstream oconv;
oconv << a_path << "/Rank_";
if (mpi.IsRootProcessor())
wildcard_path_ = oconv.str() + "*/";
oconv << mpi.GetRank<unsigned int>() << '/';
path_ = oconv.str();
Construct(invoking_file, invoking_line);
}
void Directory::Construct(const char* invoking_file, int invoking_line) const
{
// First tackle - if relevant - the 'ask' case policy:
// - The question of overwriting can only be answered on the root rank.
// - So the informations about the existence or not of the path for a given rank must be first send on root
// processor.
// - Root processor asks whether the directories must be overwritten or not. If 'no', a GracefulExit occurs.
// - Then root processor must tell the other processors to remove the directories.
// All the other policies may be handled without interprocessor communication.
if (if_already_exist_behaviour_ == if_already_exist::ask)
CollectAnswer(invoking_file, invoking_line);
// At this point, each rank may do its own bidding.
if (Folder::DoExist(path_))
{
switch(if_already_exist_behaviour_)
{
case if_already_exist::ask:
case if_already_exist::overwrite:
Folder::Remove(path_, invoking_file, invoking_line);
assert(!Folder::DoExist(path_));
Folder::Create(path_, invoking_file, invoking_line);
break;
case if_already_exist::ignore:
break;
case if_already_exist::quit:
{
std::cout << "Directory '" << path_ << "' already exists; an abortion of the program is therefore "
"scheduled." << std::endl;
throw ExceptionNS::GracefulExit(invoking_file, invoking_line);
}
}
}
else
Folder::Create(path_, invoking_file, invoking_line);
}
void Directory::CollectAnswer(const char* invoking_file, int invoking_line) const
{
assert(if_already_exist_behaviour_ == if_already_exist::ask);
decltype(auto) mpi = GetMpi();
const auto rank = mpi.GetRank<int>();
const bool do_path_exist = Folder::DoExist(path_);
std::vector<int> sent_data { do_path_exist ? rank : -1 };
std::vector<int> gathered_data;
mpi.Gather(sent_data, gathered_data);
ask_status ret = ask_status::no_preexisting;
if (mpi.IsRootProcessor())
{
if (std::any_of(gathered_data.cbegin(),
gathered_data.cend(),
[](int i)
{
return i != -1;
}))
{
ret = AskCaseRootProcessor(GetWildcardPath(),
gathered_data);
}
}
mpi.Barrier();
// Tell the ranks whether they may remove the directory.
std::vector<int> do_remove(1ul);
if (mpi.IsRootProcessor())
do_remove[0] = EnumUnderlyingType(ret);
mpi.Broadcast(do_remove);
if (do_remove.back() == EnumUnderlyingType(ask_status::remove_no))
throw ExceptionNS::GracefulExit(invoking_file, invoking_line);
}
const std::string& Directory::GetWildcardPath() const noexcept
{
assert(GetMpi().IsRootProcessor());
return wildcard_path_;
}
std::ostream& operator<<(std::ostream& out, const Directory& directory)
{
out << directory.GetPath();
return out;
}
namespace // anonymous
{
std::string RankList(const std::vector<int>& result)
{
std::vector<int> helper;
helper.reserve(result.size());
std::copy_if(result.cbegin(),
result.cend(),
std::back_inserter(helper),
[](int i)
{
return i != -1;
});
std::ostringstream oconv;
Utilities::PrintContainer<>::Do(helper, oconv);
return oconv.str();
}
ask_status AskCaseRootProcessor(const std::string& wildcard_path,
const std::vector<int>& result)
{
const std::string rank_list = RankList(result);
std::string answer;
while (answer != "y" && answer != "n")
{
do
{
if (!std::cin)
{
std::cin.clear(); // clear the states of std::cin, putting it back to `goodbit`.
std::cin.ignore(10000, '\n'); // clean-up what might remain in std::cin before using it again.
}
std::cout << "Directories '" << wildcard_path << "' already exist for ranks " << rank_list
<< ". Do you want to remove them? [y/n]"<< std::endl;
std::cin >> answer;
} while (!std::cin);
}
return answer == "y" ? ask_status::remove_yes : ask_status::remove_no;
}
} // namespace anonymous
} // namespace MoReFEM::FilesystemNS
//! \file
//
//
// Directory.hpp
// MoReFEM
//
// Created by sebastien on 01/08/2019.
//Copyright © 2019 Inria. All rights reserved.
//
#ifndef MOREFEM_x_UTILITIES_x_FILESYSTEM_x_DIRECTORY_HPP_
# define MOREFEM_x_UTILITIES_x_FILESYSTEM_x_DIRECTORY_HPP_
# include <string>
# include <sstream>
# include "Utilities/Exceptions/Exception.hpp"
# include "Utilities/Filesystem/Folder.hpp"
// ============================
//! \cond IGNORE_BLOCK_IN_DOXYGEN
// Forward declarations.
// ============================
namespace MoReFEM::Wrappers
{
class Mpi;
} // namespace MoReFEM::Wrappers
// ============================
// End of forward declarations.
//! \endcond IGNORE_BLOCK_IN_DOXYGEN
// ============================
namespace MoReFEM::FilesystemNS
{
/*!
* \brief Enum class to determine what to do when a directory already exists.
*
* - overwrite: Remove the pre-existing one and recreate it.
* - ask: Ask the end user if he wants to override or not. If he chooses not to do so, the program ends.
* Mpi is properly handled (the interface is properly rerouted to root processor which is the sole able to
* communicate with stdin).
* - quit: Quit the program if the directory exists.
* - ignore: Do not create the directory and use the existing one (including possible previous content).
*/
enum class if_already_exist
{
overwrite,
ask,
quit,
ignore
};
/*!
* \brief Class to manage properly creation if needed of directory.
*
*/
class Directory
{
public:
/// \name Special members.
///@{
/*!
* \brief Constructor.
*
* \copydoc doxygen_hide_invoking_file_and_line
*/
explicit Directory(const Wrappers::Mpi& mpi,
const std::string& path,
if_already_exist if_already_exist_behaviour,
const char* invoking_file, int invoking_line);
template<class StringT>
explicit Directory(const Directory& directory,
const StringT& subdirectory,
const char* invoking_file, int invoking_line);
//! Destructor.
~Directory() = default;
//! \copydoc doxygen_hide_copy_constructor
Directory(const Directory& rhs) = delete;
//! \copydoc doxygen_hide_move_constructor
Directory(Directory&& rhs) = delete;
//! \copydoc doxygen_hide_copy_affectation
Directory& operator=(const Directory& rhs) = delete;
//! \copydoc doxygen_hide_move_affectation
Directory& operator=(Directory&& rhs) = delete;
///@}
const std::string& GetPath() const noexcept;
operator const std::string& () const noexcept;
private:
//!
void Construct(const char* invoking_file, int invoking_line) const;
void CollectAnswer(const char* invoking_file, int invoking_line) const;
//!
const Wrappers::Mpi& GetMpi() const noexcept;
//!
if_already_exist GetIfAlreadyExistBehaviour() const noexcept;
const std::string& GetWildcardPath() const noexcept;
private:
//! Path of the directory.
std::string path_;
//! Generic path with wildcard instead of rank. Only filled for root processor.
std::string wildcard_path_;
//!
const Wrappers::Mpi& mpi_;
//! What to do if the directory already exists.
if_already_exist if_already_exist_behaviour_;
};
std::ostream& operator<<(std::ostream& out, const Directory& directory);
} // namespace MoReFEM::FilesystemNS
# include "Utilities/Filesystem/Directory.hxx"
#endif // MOREFEM_x_UTILITIES_x_FILESYSTEM_x_DIRECTORY_HPP_