diff options
author | Jan Huwald <jh@sotun.de> | 2014-02-16 13:34:30 (GMT) |
---|---|---|
committer | Jan Huwald <jh@sotun.de> | 2014-02-16 13:34:30 (GMT) |
commit | e116df4fa716795bf98c774d67e6aa102f8e1fc4 (patch) | |
tree | 50166b5c435aff66483e9af18ec321accca23ba9 | |
parent | 7bc8b6d716b3425d6e1cf74600db1667ed16d4ef (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.cc | 47 |
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(); |