Page MenuHomec4science

all_io_files.cpp
No OneTemporary

File Metadata

Created
Thu, Jun 20, 12:11

all_io_files.cpp

/* =============================================================================
Copyright (c) 2014 - 2017
F. Georget <fabieng@princeton.edu> Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
============================================================================= */
#include "all_io_files.hpp"
#include "specmicp_common/io/yaml.hpp"
#include "specmicp_common/filesystem.hpp"
#include "specmicp_common/dateandtime.hpp"
#include "specmicp_common/log.hpp"
#include <iostream>
#define SPC_IO_A_CREATION "creation_time"
#define SPC_IO_A_MODIFICATION "modification_time"
#define SPC_IO_A_CLI "command_line"
#define SPC_IO_S_INPUT "input"
#define SPC_IO_S_SOLUTION "solution"
#define SPC_IO_S_DATABASE "database"
#define SPC_IO_S_LOGS "logs"
#define SPC_IO_A_NAME "name"
#define SPC_IO_A_PATH "path"
#define SPC_IO_A_COMMENT "comment"
#define SPC_IO_A_TYPE "type"
#define SPC_IO_V_INPUT "input"
#define SPC_IO_V_OUTPUT "output"
#define SPC_IO_V_IN_OUT_PUT "input_output"
namespace specmicp {
namespace io {
struct AllIOFiles::AllIOFilesImpl
{
public:
AllIOFilesImpl(std::string filepath, AllIOFilesMode mode);
std::time_t get_creation_time();
std::time_t get_last_modification_time();
std::string get_command_line();
void save_command_line(const std::string& cli);
void add_file(const std::string& section, const IOFileInfo& file_info);
void set_modification_time();
void erase_all_files();
void erase_section_files(const std::string& section);
void erase_section_files(const std::string& section, bool only_if_output);
void parse_file();
void write_to_disk();
std::vector<std::string> get_section_names(const std::string& name);
bool get_file(
const std::string& section,
const std::string& name,
IOFileInfo& out
);
std::string get_path() {
return m_path;
}
private:
void set_absolute_path();
void remove_file(const std::string& node, std::size_t id);
void remove_file(const std::string& node, std::size_t id, bool only_if_output);
std::string m_filepath {""};
std::string m_path {""};
YAML::Node m_node;
};
// ==== Call to implementation ==== //
AllIOFiles::AllIOFiles(std::string filepath, AllIOFilesMode mode):
m_impl(utils::make_pimpl<AllIOFilesImpl>(filepath, mode))
{
}
AllIOFiles::~AllIOFiles() = default;
//! \brief Save the command line
void AllIOFiles::save_command_line(
int argc,
const char* const argv[])
{
std::string cmd;
for (auto id=0; id<argc; ++id) {
cmd += std::string(argv[id]) + ' ';
}
if (not cmd.empty()) {
cmd.pop_back();
}
m_impl->save_command_line(cmd);
}
void AllIOFiles::add_configuration_file(IOFileInfo&& file_info)
{
m_impl->add_file(SPC_IO_S_INPUT, std::move(file_info));
}
void AllIOFiles::add_database(IOFileInfo&& file_info)
{
m_impl->add_file(SPC_IO_S_DATABASE, std::move(file_info));
}
void AllIOFiles::add_solution(IOFileInfo&& file_info)
{
m_impl->add_file(SPC_IO_S_SOLUTION, std::move(file_info));
}
void AllIOFiles::add_log_file(IOFileInfo&& file_info)
{
m_impl->add_file(SPC_IO_S_LOGS, std::move(file_info));
}
//! \brief Return the creation time
std::time_t AllIOFiles::get_creation_time()
{
return m_impl->get_creation_time();
}
//! \brief Return the last modification time
std::time_t AllIOFiles::get_last_modification_time()
{
return m_impl->get_last_modification_time();
}
//! \brief Return the command line
std::string AllIOFiles::get_command_line()
{
return m_impl->get_command_line();
}
std::vector<std::string> AllIOFiles::get_configuration_file_names()
{
return m_impl->get_section_names(SPC_IO_S_INPUT);
}
bool AllIOFiles::get_configuration_file(
const std::string& name,
IOFileInfo& out
)
{
return m_impl->get_file(SPC_IO_S_INPUT, name, out);
}
std::vector<std::string> AllIOFiles::get_database_names()
{
return m_impl->get_section_names(SPC_IO_S_DATABASE);
}
bool AllIOFiles::get_database(
const std::string& name,
IOFileInfo& out
)
{
return m_impl->get_file(SPC_IO_S_DATABASE, name, out);
}
std::vector<std::string> AllIOFiles::get_solution_names()
{
return m_impl->get_section_names(SPC_IO_S_SOLUTION);
}
bool AllIOFiles::get_solution(
const std::string& name,
IOFileInfo& out
)
{
return m_impl->get_file(SPC_IO_S_SOLUTION, name, out);
}
std::vector<std::string> AllIOFiles::get_log_file_names()
{
return m_impl->get_section_names(SPC_IO_S_LOGS);
}
bool AllIOFiles::get_log_file(
const std::string& name,
IOFileInfo& out
)
{
return m_impl->get_file(SPC_IO_S_LOGS, name, out);
}
void AllIOFiles::clean_output_files() {
return m_impl->erase_all_files();
}
void AllIOFiles::sync()
{
m_impl->write_to_disk();
}
std::string AllIOFiles::get_working_dir()
{
return m_impl->get_path();
}
// ==== Implementation ==== //
std::string io_type_to_str(const IOFileType& rhs)
{
std::string ret;
switch (rhs) {
case IOFileType::Input:
ret = SPC_IO_V_INPUT;
break;
case IOFileType::Output:
ret = SPC_IO_V_OUTPUT;
break;
case IOFileType::Input_Output:
ret = SPC_IO_V_IN_OUT_PUT;
break;
default:
ERROR_THROW("Invalid file type (IOFileType) when converting to string");
}
return ret;
}
IOFileType str_to_io_type(const std::string& rhs)
{
IOFileType type;
if (rhs == SPC_IO_V_INPUT) {
type = IOFileType::Input;
} else if (rhs == SPC_IO_V_OUTPUT) {
type = IOFileType::Output;
} else if (rhs == SPC_IO_V_IN_OUT_PUT) {
type = IOFileType::Input_Output;
} else {
ERROR_THROW("Invalid file type '" +
rhs + "' when converting to IOFileType");
}
return type;
}
} // end namespace io
} // end namespace specmicp
// YAML conversion
namespace YAML {
template<>
struct convert<specmicp::io::IOFileInfo> {
static Node encode(const specmicp::io::IOFileInfo& rhs) {
Node node;
node[SPC_IO_A_NAME] = rhs.name;
node[SPC_IO_A_PATH] = rhs.filepath;
node[SPC_IO_A_TYPE] = io_type_to_str(rhs.type);
if (not rhs.comment.empty())
{
node[SPC_IO_A_COMMENT] = rhs.comment;
}
return node;
}
static bool decode(const Node& node, specmicp::io::IOFileInfo& rhs) {
if( (not node.IsMap())
or (not node[SPC_IO_A_NAME])
or (not node[SPC_IO_A_PATH])
or (not node[SPC_IO_A_TYPE])) {
return false;
}
specmicp::io::IOFileType type =
specmicp::io::str_to_io_type(node[SPC_IO_A_TYPE].as<std::string>());
if (node[SPC_IO_A_COMMENT]) {
rhs = specmicp::io::IOFileInfo(
node[SPC_IO_A_NAME].as<std::string>(),
node[SPC_IO_A_PATH].as<std::string>(),
node[SPC_IO_A_COMMENT].as<std::string>(),
type
);
}
else {
rhs = specmicp::io::IOFileInfo(
node[SPC_IO_A_NAME].as<std::string>(),
node[SPC_IO_A_PATH].as<std::string>(),
type
);
}
return true;
}
};
}
namespace specmicp {
namespace io {
AllIOFiles::AllIOFilesImpl::AllIOFilesImpl(std::string filepath, AllIOFilesMode mode)
{
auto path_exists = utils::path_exists(filepath);
m_filepath = filepath;
if (path_exists) {
if (not utils::is_file(filepath)) {
ERROR_THROW("IOError : " + filepath + " is not a file.");
}
if ( mode == AllIOFilesMode::ErrorIfExist) {
ERROR_THROW("IOError : " + filepath + " already exists");
}
else if ( mode == AllIOFilesMode::Write) {
auto other = AllIOFilesImpl(filepath, AllIOFilesMode::Read);
other.erase_all_files();
}
else if ( mode == AllIOFilesMode::Read) {
parse_file();
}
}
if ( (mode == AllIOFilesMode::ErrorIfExist) or
(mode == AllIOFilesMode::Write)
)
{
m_node[SPC_IO_A_CREATION] = dateandtime::now();
set_modification_time();
}
set_absolute_path();
}
void AllIOFiles::AllIOFilesImpl::add_file(
const std::string& section,
const IOFileInfo& file_info
)
{
m_node[section].push_back(YAML::Node(file_info));
set_modification_time();
}
void AllIOFiles::AllIOFilesImpl::set_absolute_path() {
auto splitted = utils::split_filepath(m_filepath);
auto& dir = splitted[0];
if (not dir.empty()) {
if (not utils::is_path_absolute(dir)) {
std::string error;
auto tmp = utils::relative_to_absolute(dir, error);
if (not error.empty()) {
ERROR_THROW(error);
}
m_path = tmp;
} else {
m_path = dir;
}
} else {
m_path = utils::get_current_directory();
}
}
void AllIOFiles::AllIOFilesImpl::parse_file()
{
m_node = parse_yaml_file(m_filepath);
}
void AllIOFiles::AllIOFilesImpl::erase_all_files()
{
erase_section_files(SPC_IO_S_LOGS);
erase_section_files(SPC_IO_S_SOLUTION);
// Do not erase db if input
erase_section_files(SPC_IO_S_DATABASE, true);
// DO not erase input !
erase_section_files(SPC_IO_S_INPUT, true);
utils::remove_file(m_filepath);
}
void AllIOFiles::AllIOFilesImpl::erase_section_files(const std::string& section)
{
for (std::size_t id=0; id<m_node[section].size(); ++id) {
remove_file(section, id);
}
}
void AllIOFiles::AllIOFilesImpl::erase_section_files(
const std::string& section,
bool only_if_output)
{
for (std::size_t id=0; id<m_node[section].size(); ++id) {
remove_file(section, id, only_if_output);
}
}
void AllIOFiles::AllIOFilesImpl::remove_file(
const std::string& section,
std::size_t id)
{
auto path = m_node[section][id][SPC_IO_A_PATH].as<std::string>();
if (not utils::is_path_absolute(path)) {
path = utils::complete_path(m_path, path);
}
DEBUG << "Removing : " << path;
utils::remove_file(path);
m_node[section].remove(id);
set_modification_time();
}
void AllIOFiles::AllIOFilesImpl::remove_file(
const std::string& section,
std::size_t id,
bool only_if_output)
{
IOFileInfo info = m_node[section][id].as<IOFileInfo>();
if (info.type != IOFileType::Output) {
return;
}
auto path = info.filepath;
if (not utils::is_path_absolute(path)) {
path = utils::complete_path(m_path, path);
}
DEBUG << "Removing : " << path;
utils::remove_file(path);
m_node[section].remove(id);
set_modification_time();
}
void AllIOFiles::AllIOFilesImpl::save_command_line(const std::string& cli)
{
m_node[SPC_IO_A_CLI] = cli;
set_modification_time();
}
void AllIOFiles::AllIOFilesImpl::set_modification_time()
{
m_node[SPC_IO_A_MODIFICATION] = dateandtime::now();
}
void AllIOFiles::AllIOFilesImpl::write_to_disk()
{
YAML::Emitter yaml_emitter;
yaml_emitter << m_node;
DEBUG << "Save AllIOFile to " << m_filepath
<< " - " << utils::get_current_directory();
DEBUG << "YAML emitter size : " << yaml_emitter.size();
DEBUG << "Before emitter : " << m_node[SPC_IO_A_CLI];
save_yaml(m_filepath, yaml_emitter);
}
std::time_t AllIOFiles::AllIOFilesImpl::get_creation_time()
{
return dateandtime::from_text(m_node[SPC_IO_A_CREATION].as<std::string>());
}
std::time_t AllIOFiles::AllIOFilesImpl::get_last_modification_time()
{
return dateandtime::from_text(m_node[SPC_IO_A_MODIFICATION].as<std::string>());
}
std::string AllIOFiles::AllIOFilesImpl::get_command_line()
{
return m_node[SPC_IO_A_CLI].as<std::string>();
}
std::vector<std::string> AllIOFiles::AllIOFilesImpl::get_section_names(
const std::string& section)
{
const auto sec_node = m_node[section];
std::vector<std::string> names;
names.reserve(sec_node.size());
for (const auto& node: sec_node) {
names.push_back(node[SPC_IO_A_NAME].as<std::string>());
}
return names;
}
bool AllIOFiles::AllIOFilesImpl::get_file(
const std::string& section,
const std::string& name,
IOFileInfo& out
)
{
const YAML::Node sec_node = m_node[section];
for (const auto& node: sec_node) {
if ( node[SPC_IO_A_NAME]
and node[SPC_IO_A_NAME].as<std::string>() == name)
{
out = node.as<IOFileInfo>();
return true;
}
}
return false;
}
} // end namespace io
} // end namespace specmicp

Event Timeline