Various filesystem refactorings

– DataTree::packageDir() now takes a std::string_view, returns a
  std::filesystem::path, and no longer creates that directory
– DataTree::writeToFileIfModified() now takes a std::filesystem::path as
  argument
– Do not call DataTree::writeToFileIfModified() for generating MATLAB/Octave
  files, since it does not work (the directory inside which the file is written
  has been deleted by the preprocessor just before)
– Consistently use DataTree::packageDir() everywhere (for compatibility with
  planner_objective)
master
Sébastien Villemot 2022-10-11 15:59:56 +02:00
parent 198ff70bce
commit 93054cf692
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
10 changed files with 137 additions and 70 deletions

View File

@ -20,7 +20,6 @@
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <regex>
#include <algorithm>
#include <iterator>
#include <filesystem>
@ -962,17 +961,17 @@ DataTree::strsplit(string_view str, char delim)
return result;
}
string
DataTree::packageDir(const string &package)
filesystem::path
DataTree::packageDir(string_view package)
{
regex pat{R"(\.)"};
string dirname = "+" + regex_replace(package, pat, "/+");
filesystem::create_directories(dirname);
return dirname;
filesystem::path d;
for (const auto &it : strsplit(move(package), '.'))
d /= "+" + it;
return d;
}
void
DataTree::writeToFileIfModified(stringstream &new_contents, const string &filename)
DataTree::writeToFileIfModified(stringstream &new_contents, const filesystem::path &filename)
{
ifstream old_file{filename, ios::in | ios::binary};
if (old_file.is_open()
@ -986,7 +985,7 @@ DataTree::writeToFileIfModified(stringstream &new_contents, const string &filena
ofstream new_file{filename, ios::out | ios::binary};
if (!new_file.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
copy(istreambuf_iterator<char>{new_contents}, istreambuf_iterator<char>{},

View File

@ -28,6 +28,8 @@
#include <cmath>
#include <utility>
#include <memory>
#include <filesystem>
#include <string_view>
#include "SymbolTable.hh"
#include "NumericalConstants.hh"
@ -109,7 +111,7 @@ protected:
/* Writes the contents of “new_contents” to the file “filename”. However, if
the file already exists and would not be modified by this operation, then do
nothing. */
static void writeToFileIfModified(stringstream &new_contents, const string &filename);
static void writeToFileIfModified(stringstream &new_contents, const filesystem::path &filename);
private:
constexpr static int constants_precision{16};
@ -361,11 +363,10 @@ public:
static vector<string> strsplit(string_view str, char delim);
/*! Takes a MATLAB/Octave package name (possibly with several levels nested using dots),
and returns the name of the corresponding filesystem directory (which
is created by the function if it does not exist).
and returns the path to the corresponding filesystem directory.
In practice the package nesting is used for the planner_objective (stored
inside +objective subdir). */
static string packageDir(const string &package);
static filesystem::path packageDir(string_view package);
};
inline expr_t

View File

@ -223,16 +223,16 @@ DynamicModel::writeDynamicPerBlockMFiles(const string &basename) const
int nze_exo = blocks_derivatives_exo[blk].size();
int nze_exo_det = blocks_derivatives_exo_det[blk].size();
string filename = packageDir(basename + ".block") + "/dynamic_" + to_string(blk+1) + ".m";
filesystem::path filename {packageDir(basename) / "+block" / ("dynamic_" + to_string(blk+1) + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output << "%" << endl
<< "% " << filename << " : Computes dynamic version of one block" << endl
<< "% " << filename.string() << " : Computes dynamic version of one block" << endl
<< "%" << endl
<< "% Warning : this file is generated automatically by Dynare" << endl
<< "% from model file (.mod)" << endl << endl
@ -987,11 +987,11 @@ DynamicModel::printNonZeroHessianEquations(ostream &output) const
void
DynamicModel::writeDynamicBlockMFile(const string &basename) const
{
string filename = packageDir(basename) + "/dynamic.m";
filesystem::path filename {packageDir(basename) / "dynamic.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -1102,7 +1102,7 @@ DynamicModel::writeDynamicBlockCFile(const string &basename, vector<filesystem::
output.close();
per_block_object_files.push_back(filename);
compileMEX("+" + basename, "dynamic", mexext, per_block_object_files, matlabroot, dynareroot);
compileMEX(packageDir(basename), "dynamic", mexext, per_block_object_files, matlabroot, dynareroot);
}
void
@ -1116,11 +1116,11 @@ DynamicModel::writeDynamicMWrapperFunction(const string &basename, const string
else if (ending == "g3")
name = "dynamic_resid_g1_g2_g3";
string filename = packageDir(basename) + "/" + name + ".m";
filesystem::path filename {packageDir(basename) / (name + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -1164,11 +1164,11 @@ DynamicModel::writeDynamicMFileHelper(const string &basename,
const ostringstream &init_s, const ostringstream &end_s,
const ostringstream &s, const ostringstream &s_tt) const
{
string filename = packageDir(basename) + "/" + name_tt + ".m";
filesystem::path filename {packageDir(basename) / (name_tt + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -1201,11 +1201,11 @@ DynamicModel::writeDynamicMFileHelper(const string &basename,
<< "end" << endl;
output.close();
filename = packageDir(basename) + "/" + name + ".m";
filename = packageDir(basename) / (name + ".m");
output.open(filename, ios::out | ios::binary);
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -1245,11 +1245,11 @@ DynamicModel::writeDynamicMFileHelper(const string &basename,
void
DynamicModel::writeDynamicMCompatFile(const string &basename) const
{
string filename = packageDir(basename) + "/dynamic.m";
filesystem::path filename {packageDir(basename) / "dynamic.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
int ntt { static_cast<int>(temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size()) };
@ -1291,7 +1291,7 @@ DynamicModel::writeDynamicJacobianNonZeroEltsFile(const string &basename) const
sort(nzij_current.begin(), nzij_current.end());
sort(nzij_fwrd.begin(), nzij_fwrd.end());
ofstream output{"+" + basename + "/dynamic_g1_nz.m", ios::out | ios::binary};
ofstream output{packageDir(basename) / "dynamic_g1_nz.m", ios::out | ios::binary};
output << "function [nzij_pred, nzij_current, nzij_fwrd] = dynamic_g1_nz()" << endl
<< "% Returns the coordinates of non-zero elements in the Jacobian, in column-major order, for each lead/lag (only for endogenous)" << endl;
auto print_nzij = [&output](const vector<pair<int, int>> &nzij, const string &name) {
@ -3472,6 +3472,16 @@ DynamicModel::writeDynamicFile(const string &basename, bool block, bool use_dll,
model_dir /= "model";
if (use_dll)
create_directories(model_dir / "src");
if (!julia)
{
auto plusfolder {packageDir(basename)};
/* The following is not a duplicate of the same call from
ModFile::writeMOutput(), because of planner_objective which needs its
+objective subdirectory */
create_directories(plusfolder);
if (block && !use_dll)
create_directories(plusfolder / "+block");
}
create_directories(model_dir / "bytecode");
if (block)
@ -3543,7 +3553,22 @@ DynamicModel::writeSetAuxiliaryVariables(const string &basename, bool julia) con
output << "end" << endl
<< "end" << endl;
writeToFileIfModified(output, julia ? basename + "DynamicSetAuxiliarySeries.jl" : packageDir(basename) + "/" + func_name + ".m");
if (julia)
writeToFileIfModified(output, basename + "DynamicSetAuxiliarySeries.jl");
else
{
/* Calling writeToFileIfModified() is useless here since we write inside
a subdirectory deleted at each preprocessor run. */
filesystem::path filename {packageDir(basename) / (func_name + ".m")};
ofstream output_file{filename, ios::out | ios::binary};
if (!output_file.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output_file << output.str();
output_file.close();
}
}
void

View File

@ -837,11 +837,11 @@ DynamicModel::writeParamsDerivativesFile(const string &basename) const
auto [tt_output, rp_output, gp_output, rpp_output, gpp_output, hp_output, g3p_output]
{ writeParamsDerivativesFileHelper<output_type>() };
string filename { julia ? basename + "DynamicParamsDerivs.jl" : packageDir(basename) + "/dynamic_params_derivs.m" };
const filesystem::path filename {julia ? filesystem::path{basename + "DynamicParamsDerivs.jl"} : packageDir(basename) / "dynamic_params_derivs.m"};
ofstream paramsDerivsFile { filename, ios::out | ios::binary };
if (!paramsDerivsFile.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}

View File

@ -782,6 +782,14 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
const filesystem::path &matlabroot,
const filesystem::path &dynareroot, bool onlymodel, bool gui, bool notime) const
{
if (basename.empty())
{
cerr << "ERROR: Missing file name" << endl;
exit(EXIT_FAILURE);
}
auto plusfolder {DataTree::packageDir(basename)};
bool hasModelChanged = !dynamic_model.isChecksumMatching(basename) || !check_model_changes;
if (hasModelChanged)
{
@ -793,7 +801,7 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
it before deleting it (the renaming must occur in the same directory,
otherwise it may file if the destination is not on the same
filesystem). */
if (filesystem::path plusfolder{"+" + basename}; exists(plusfolder))
if (exists(plusfolder))
{
if (exists(plusfolder / "+objective"))
{
@ -811,18 +819,12 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
filesystem::remove_all(basename + "/model/bytecode");
}
if (!basename.size())
{
cerr << "ERROR: Missing file name" << endl;
exit(EXIT_FAILURE);
}
filesystem::create_directory("+" + basename);
string fname = "+" + basename + "/driver.m";
create_directory(plusfolder);
filesystem::path fname {plusfolder / "driver.m"};
ofstream mOutputFile{fname, ios::out | ios::binary};
if (!mOutputFile.is_open())
{
cerr << "ERROR: Can't open file " << fname << " for writing" << endl;
cerr << "ERROR: Can't open file " << fname.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}

View File

@ -259,7 +259,22 @@ SteadyStateModel::writeSteadyStateFile(const string &basename, bool julia) const
if (julia)
output << "end" << endl << "end" << endl;
writeToFileIfModified(output, julia ? basename + "SteadyState2.jl" : packageDir(basename) + "/steadystate.m");
if (julia)
writeToFileIfModified(output, basename + "SteadyState2.jl");
else
{
/* Calling writeToFileIfModified() is useless here since we write inside
a subdirectory deleted at each preprocessor run. */
filesystem::path filename {packageDir(basename) / "steadystate.m"};
ofstream output_file{filename, ios::out | ios::binary};
if (!output_file.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output_file << output.str();
output_file.close();
}
}
void
@ -407,11 +422,11 @@ Epilogue::writeEpilogueFile(const string &basename) const
void
Epilogue::writeStaticEpilogueFile(const string &basename) const
{
string filename = packageDir(basename) + "/epilogue_static.m";
filesystem::path filename {packageDir(basename) / "epilogue_static.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -445,11 +460,11 @@ Epilogue::writeStaticEpilogueFile(const string &basename) const
void
Epilogue::writeDynamicEpilogueFile(const string &basename) const
{
string filename = packageDir(basename) + "/epilogue_dynamic.m";
filesystem::path filename {packageDir(basename) / "epilogue_dynamic.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}

View File

@ -1031,7 +1031,7 @@ ModelTree::writeModelCFile(const string &basename, const string &mexext,
output.close();
object_files.push_back(filename);
compileMEX("+" + basename, dynamic ? "dynamic" : "static", mexext, object_files, matlabroot,
compileMEX(packageDir(basename), dynamic ? "dynamic" : "static", mexext, object_files, matlabroot,
dynareroot);
}

View File

@ -104,15 +104,15 @@ StaticModel::writeStaticPerBlockMFiles(const string &basename) const
{
BlockSimulationType simulation_type = blocks[blk].simulation_type;
string filename = packageDir(basename + ".block") + "/static_" + to_string(blk+1) + ".m";
filesystem::path filename {packageDir(basename) / "+block" / ("static_" + to_string(blk+1) + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output << "%" << endl
<< "% " << filename << " : Computes static version of one block" << endl
<< "% " << filename.string() << " : Computes static version of one block" << endl
<< "%" << endl
<< "% Warning : this file is generated automatically by Dynare" << endl
<< "% from model file (.mod)" << endl << endl
@ -465,11 +465,11 @@ StaticModel::writeStaticMWrapperFunction(const string &basename, const string &e
else if (ending == "g3")
name = "static_resid_g1_g2_g3";
string filename = packageDir(basename) + "/" + name + ".m";
filesystem::path filename {packageDir(basename) / (name + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -513,11 +513,11 @@ StaticModel::writeStaticMFileHelper(const string &basename,
const ostringstream &init_s, const ostringstream &end_s,
const ostringstream &s, const ostringstream &s_tt) const
{
string filename = packageDir(basename) + "/" + name_tt + ".m";
filesystem::path filename {packageDir(basename) / (name_tt + ".m")};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -545,11 +545,11 @@ StaticModel::writeStaticMFileHelper(const string &basename,
<< "end" << endl;
output.close();
filename = packageDir(basename) + "/" + name + ".m";
filename = packageDir(basename) / (name + ".m");
output.open(filename, ios::out | ios::binary);
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -585,11 +585,11 @@ StaticModel::writeStaticMFileHelper(const string &basename,
void
StaticModel::writeStaticMCompatFile(const string &basename) const
{
string filename = packageDir(basename) + "/static.m";
filesystem::path filename {packageDir(basename) / "static.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
int ntt { static_cast<int>(temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size()) };
@ -845,6 +845,16 @@ StaticModel::writeStaticFile(const string &basename, bool block, bool use_dll, c
model_dir /= "model";
if (use_dll)
create_directories(model_dir / "src");
if (!julia)
{
auto plusfolder {packageDir(basename)};
/* The following is not a duplicate of the same call from
ModFile::writeMOutput(), because of planner_objective which needs its
+objective subdirectory */
create_directories(plusfolder);
if (block && !use_dll)
create_directories(plusfolder / "+block");
}
create_directories(model_dir / "bytecode");
if (block)
@ -894,12 +904,12 @@ StaticModel::exoPresentInEqs() const
void
StaticModel::writeStaticBlockMFile(const string &basename) const
{
string filename = packageDir(basename) + "/static.m";
filesystem::path filename {packageDir(basename) / "static.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
@ -999,7 +1009,7 @@ StaticModel::writeStaticBlockCFile(const string &basename, vector<filesystem::pa
output.close();
per_block_object_files.push_back(filename);
compileMEX("+" + basename, "static", mexext, per_block_object_files, matlabroot, dynareroot);
compileMEX(packageDir(basename), "static", mexext, per_block_object_files, matlabroot, dynareroot);
}
void
@ -1205,7 +1215,22 @@ StaticModel::writeSetAuxiliaryVariables(const string &basename, bool julia) cons
output << "end" << endl
<< "end" << endl;
writeToFileIfModified(output, julia ? basename + "SetAuxiliaryVariables.jl" : packageDir(basename) + "/" + func_name + ".m");
if (julia)
writeToFileIfModified(output, basename + "SetAuxiliaryVariables.jl");
else
{
/* Calling writeToFileIfModified() is useless here since we write inside
a subdirectory deleted at each preprocessor run. */
filesystem::path filename {packageDir(basename) / (func_name + ".m")};
ofstream output_file{filename, ios::out | ios::binary};
if (!output_file.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output_file << output.str();
output_file.close();
}
}
void

View File

@ -225,11 +225,11 @@ StaticModel::writeParamsDerivativesFile(const string &basename) const
{ writeParamsDerivativesFileHelper<output_type>() };
// g3p_output is ignored
string filename { julia ? basename + "StaticParamsDerivs.jl" : packageDir(basename) + "/static_params_derivs.m" };
filesystem::path filename {julia ? filesystem::path{basename + "StaticParamsDerivs.jl"} : packageDir(basename) / "static_params_derivs.m"};
ofstream paramsDerivsFile { filename, ios::out | ios::binary };
if (!paramsDerivsFile.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}

View File

@ -246,11 +246,11 @@ TrendComponentModelTable::writeOutput(const string &basename, ostream &output) c
if (names.empty())
return;
string filename = "+" + basename + "/trend_component_ar_a0.m";
const filesystem::path filename {DataTree::packageDir(basename) / "trend_component_ar_a0.m"};
ofstream ar_ec_output{filename, ios::out | ios::binary};
if (!ar_ec_output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
ar_ec_output << "function [AR, A0, A0star] = trend_component_ar_a0(model_name, params)" << endl
@ -427,11 +427,11 @@ VarModelTable::writeOutput(const string &basename, ostream &output) const
if (names.empty())
return;
string filename = "+" + basename + "/varmatrices.m";
const filesystem::path filename {DataTree::packageDir(basename) / "varmatrices.m"};
ofstream ar_output{filename, ios::out | ios::binary};
if (!ar_output.is_open())
{
cerr << "Error: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
ar_output << "function [ar, a0, constants] = varmatrices(model_name, params, reducedform)" << endl
@ -1751,11 +1751,11 @@ PacModelTable::writeTargetCoefficientsFile(const string &basename) const
if (target_info.empty())
return;
string filename = DataTree::packageDir(basename) + "/pac_target_coefficients.m";
filesystem::path filename {DataTree::packageDir(basename) / "pac_target_coefficients.m"};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
output << "function coeffs = pac_target_coefficients(model_name, params)" << endl;