summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Huwald <jh@sotun.de>2014-02-16 13:34:30 (GMT)
committerJan Huwald <jh@sotun.de>2014-02-16 13:34:30 (GMT)
commite116df4fa716795bf98c774d67e6aa102f8e1fc4 (patch)
tree50166b5c435aff66483e9af18ec321accca23ba9
parent7bc8b6d716b3425d6e1cf74600db1667ed16d4ef (diff)
write output to temporary file, commit only after completion
cmdline() is modified to write into <output_file>~ and only after succesful completion of the given command rename this file into <output_file>. In case of failure the file is deleted. This prevents dangling errorneous output files and overwriting valid (but old) files with new trash. This patch is required for robust use of OpenSCAD in Makefiles. In case of a crash the output file must not be touched. Otherwise the update file date will trick Makefile into assuming a succesful build.
-rw-r--r--src/openscad.cc47
1 files changed, 32 insertions, 15 deletions
diff --git a/src/openscad.cc b/src/openscad.cc
index d190cc0..36ba68c 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -217,7 +217,7 @@ static bool assert_root_2d(CGAL_Nef_polyhedron &nef) {
return true;
};
-int cmdline(const char *deps_output_file, const string &filename, Camera &camera, const char *output_file, const fs::path &original_path, Render::type renderer, string application_name)
+int cmdline(const char *deps_output_file, const string &filename, Camera &camera, const string output_file, const fs::path &original_path, Render::type renderer, string application_name)
{
CGAL_Nef_polyhedron root_N;
Tree tree;
@@ -239,13 +239,11 @@ int cmdline(const char *deps_output_file, const string &filename, Camera &camera
root_N = cgalevaluator->evaluateCGALMesh(*tree.root());
if (!assert_root_3d_simple(root_N)) return 1;
export_off(&root_N, fstream);
- fstream.close();
return 0; }},
{"dxf", [&] {
root_N = cgalevaluator->evaluateCGALMesh(*tree.root());
if (!assert_root_2d(root_N)) return 1;
export_dxf(&root_N, fstream);
- fstream.close();
return 0; }},
{"png", [&] {
switch (renderer) {
@@ -267,11 +265,9 @@ int cmdline(const char *deps_output_file, const string &filename, Camera &camera
return 0; }},
{"term", [&] {
// TODO: check wether CWD is correct at this point
- vector<shared_ptr<CSGTerm> > highlight_terms;
- vector<shared_ptr<CSGTerm> > background_terms;
-
PolySetCGALEvaluator psevaluator(*cgalevaluator);
CSGTermEvaluator csgRenderer(tree, &psevaluator);
+ vector<shared_ptr<CSGTerm> > highlight_terms, background_terms;
shared_ptr<CSGTerm> root_raw_term = csgRenderer.evaluateCSGTerm(*root_node, highlight_terms, background_terms);
if (!root_raw_term) {
@@ -301,12 +297,11 @@ int cmdline(const char *deps_output_file, const string &filename, Camera &camera
return 1;
}
- // Open the output file
- fstream.open(output_file, (suffix == "png") ? std::ios::binary : std::ios::out);
- if (!fstream.is_open()) {
- PRINTB("Can't open file \"%s\" for export", output_file);
- }
-
+ // Open the output file early if it is an echo stream
+ unique_ptr<Echostream> echostream;
+ string temp_output_file = output_file + "~";
+ if (suffix == "echo")
+ echostream.reset(new Echostream(temp_output_file.c_str()));
// Init parser, top_con
const string application_path = boosty::stringy(boosty::absolute(boost::filesystem::path(application_name).parent_path()));
@@ -321,9 +316,6 @@ int cmdline(const char *deps_output_file, const string &filename, Camera &camera
#if 0 && DEBUG
top_ctx.dump(NULL, NULL);
#endif
- unique_ptr<Echostream> echostream;
- if (suffix == "echo")
- echostream.reset( new Echostream( output_file ) );
ModuleInstantiation root_inst("group");
AbstractNode *absolute_root_node;
@@ -383,9 +375,34 @@ int cmdline(const char *deps_output_file, const string &filename, Camera &camera
}
}
+ // Open output file late to catch errors before writing anything to disk
+ if (suffix != "echo") {
+ fstream.open(temp_output_file, (suffix == "png") ? std::ios::binary : std::ios::out);
+ if (!fstream.is_open()) {
+ PRINTB("Can't open file \"%s\" for export", temp_output_file);
+ return 1;
+ }
+ }
+
// Call the intended action
auto ret = actions[suffix]();
+ // Commit the file if succesfull, delete it otherwise.
+ if (!ret) {
+ // Success
+ if (rename(temp_output_file.c_str(), output_file.c_str())) {
+ PRINTB("Can't rename \"%s\" to \"%s\"", temp_output_file % output_file);
+ return 1;
+ }
+ }else{
+ // Failure
+ if (remove(temp_output_file.c_str())) {
+ PRINTB("Can't remove \"%s\"", temp_output_file);
+ return 1;
+ }
+ fstream.close();
+ }
+
// Clean up
delete root_node;
fstream.close();
contact: Jan Huwald // Impressum