diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 9cde583f3..ebdebf9ab 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef USE_WX #include "GUI/GUI.hpp" @@ -48,8 +49,6 @@ int CLI::run(int argc, char **argv) { return 1; } - // TODO: validate this->config (min, max etc.) - // parse actions and transform options for (auto const &opt_key : opt_order) { if (cli_actions_config_def.has(opt_key)) this->actions.push_back(opt_key); @@ -293,7 +292,7 @@ int CLI::run(int argc, char **argv) { const std::string outfile = this->output_filepath(model, IO::Gcode); try { print.export_gcode(outfile); - } catch (InvalidPrintException &e) { + } catch (std::runtime_error &e) { boost::nowide::cerr << e.what() << std::endl; return 1; } diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index c6769c2cc..64dadeb2b 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -9,7 +9,17 @@ #include #include #include +#include +#include #include +#include +#include + +#ifdef __cpp_lib_quoted_string_io + #include +#else + #include +#endif namespace Slic3r { @@ -717,7 +727,6 @@ Print::export_gcode(std::ostream& output, bool quiet) auto export_handler {Slic3r::PrintGCode(*this, output)}; export_handler.output(); - } void @@ -726,10 +735,46 @@ Print::export_gcode(std::string outfile, bool quiet) // compute the actual output filepath outfile = this->output_filepath(outfile); - std::ofstream outstream(outfile); + // write G-code to a temporary file in order to make the export atomic + const std::string tempfile{ outfile + ".tmp" }; + std::ofstream outstream(tempfile); this->export_gcode(outstream); - // TODO: export_gcode() is not ported completely from Perl + // rename the temporary file to the destination file + // When renaming, some other application (thank you, Windows Explorer) + // may keep the file locked. Try to wait a bit and then rename the file again. + for (int i = 0; std::rename(tempfile.c_str(), outfile.c_str()) != 0; ++i) { + if (i == 4) { + std::stringstream ss; + ss << "Failed to remove the output G-code file from " + << tempfile << " to " << outfile << ". Is " << tempfile << " locked?"; + throw std::runtime_error(ss.str()); + } else { + // Wait for 1/4 seconds and try to rename once again. + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + } + + // run post-processing scripts + if (!this->config.post_process.values.empty()) { + if (this->status_cb != nullptr) + this->status_cb(95, "Running post-processing scripts..."); + + this->config.setenv_(); + for (std::string ppscript : this->config.post_process.values) { + #ifdef __cpp_lib_quoted_string_io + ppscript += " " + std::quoted(outfile); + #else + boost::replace_all(ppscript, "\"", "\\\""); + ppscript += " \"" + outfile + "\""; + #endif + system(ppscript.c_str()); + + // TODO: system() should be only used if user enabled an option for explicitly + // supporting arguments, otherwise we should use exec*() and call the executable + // directly without launching a shell. #4000 + } + } }