From 486ca1bb89df68379ed541fa54a4a93350e816aa Mon Sep 17 00:00:00 2001 From: Jordan Evens Date: Mon, 22 Jun 2026 16:27:52 +0000 Subject: [PATCH] FIX: #35 don't create invalid settings file when weather input is missing --- src/cpp/fs/Settings.cpp | 51 +++++++++++++++++++++++++++++++++-------- src/cpp/fs/Settings.h | 1 + src/cpp/fs/Util.h | 1 + 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/cpp/fs/Settings.cpp b/src/cpp/fs/Settings.cpp index 25def2048ac..43cd46fb225 100644 --- a/src/cpp/fs/Settings.cpp +++ b/src/cpp/fs/Settings.cpp @@ -402,23 +402,20 @@ string format_section_header(const string& section, int width = 80, int side_wid "{}\n{}{: ^{}}{}\n{}\n", hr, side, section, width - (2 * side_width), side, hr ); } -void Settings::saveTo(const string& output_directory) const noexcept +string Settings::create(const pushd& dir) const { - make_directory_recursive(output_directory); - const pushd dir{output_directory}; - const auto filename = "settings.ini"; - ofstream out{filename}; - auto add_comment = [&](const string& comment) { out << "#" << comment << "\n"; }; + stringstream buffer{}; + auto add_comment = [&](const string& comment) { buffer << "#" << comment << "\n"; }; auto add_section = [&](const string& section) { auto header = format_section_header(section); - out << header; + buffer << header; }; auto put = [&](const string& key, const string& comment, const auto& value) { // FIX: use original string instead of parsed and stringified input so nothing can change static constexpr auto MAX_PRECISION = std::numeric_limits::digits10 + 1; // make sure we don't lose precision or results will differ when run with settings file add_comment(" " + comment); - out << key << " = " << std::setprecision(MAX_PRECISION) << value << "\n"; + buffer << key << " = " << std::setprecision(MAX_PRECISION) << value << "\n"; }; // HACK: just hardcode how this works since it's the opposite of parsing // // FIX: this should always just be whatever folder the settings file is in? @@ -441,7 +438,14 @@ void Settings::saveTo(const string& output_directory) const noexcept put("MODE", mode_help, to_string(mode)); if (!wx_file_name.empty()) { - put("WX", "weather file path", relative(wx_file_name.canonical()).c_str()); + auto wx_file = relative(wx_file_name.canonical()); + if (!file_exists(wx_file.c_str())) + { + throw std::runtime_error( + std::format("Weather input file {} not found", wx_file_name.intended_path()) + ); + } + put("WX", "weather file path", wx_file.c_str()); } put("LOG_FILE_NAME", "log file name (created in output directoy)", log_file_name.c_str()); if (!perimeter.empty()) @@ -608,6 +612,35 @@ void Settings::saveTo(const string& output_directory) const noexcept minimum_active_simulation_count ); put("MAXIMUM_SIMULATIONS", "maximum number of simulations to do", maximum_simulation_count); + return buffer.str(); +} +void Settings::saveTo(const string& output_directory) const noexcept +{ + try + { + make_directory_recursive(output_directory); + // HACK: create() might depend on being in directory + const pushd dir{output_directory}; + const auto contents = create(dir); + const auto filename = "settings.ini"; + try + { + ofstream out{filename}; + out << contents; + } + catch (std::exception& ex) + { + if (file_exists(filename)) + { + std::filesystem::remove(filename); + } + throw ex; + } + } + catch (std::exception& ex) + { + exit(logging::fatal(ex, "Unable to output settings file")); + } } FwiWeather Settings::get_weather() const { diff --git a/src/cpp/fs/Settings.h b/src/cpp/fs/Settings.h index 9fe6ecac043..105387d0170 100644 --- a/src/cpp/fs/Settings.h +++ b/src/cpp/fs/Settings.h @@ -73,6 +73,7 @@ class Settings const string getBinaryDirectory() const noexcept; Settings() = delete; Settings(const string dir_binary, const string dir_root) noexcept; + string create(const pushd& dir) const; // save to directory in same format parse expects void saveTo(const string& output_directory) const noexcept; bool found(const string& key) const noexcept diff --git a/src/cpp/fs/Util.h b/src/cpp/fs/Util.h index 6a64367731d..93e0140b7d6 100644 --- a/src/cpp/fs/Util.h +++ b/src/cpp/fs/Util.h @@ -485,6 +485,7 @@ class LazyPath : LazyPath(string(dir_root), string(path)) { } bool empty() const { return path_.empty(); } + string intended_path() const noexcept { return std::format("{}/{}", dir_root_, path_); } const char* canonical() const { if (nullptr == canonical_path_)