Finish porting export_gcode() - atomic write and post-processing scripts

This commit is contained in:
Alessandro Ranellucci 2018-11-20 10:09:41 +01:00 committed by Joseph Lenox
parent fac31616c8
commit 3b2c9cbf7d
2 changed files with 50 additions and 6 deletions

View File

@ -17,6 +17,7 @@
#include <boost/filesystem.hpp>
#include <boost/nowide/args.hpp>
#include <boost/nowide/iostream.hpp>
#include <stdexcept>
#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;
}

View File

@ -9,7 +9,17 @@
#include <algorithm>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <thread>
#include <sstream>
#ifdef __cpp_lib_quoted_string_io
#include <iomanip>
#else
#include <boost/algorithm/string.hpp>
#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
}
}
}