Any comments on this? Anyone care to test it? If you like Export>HTML or View>HTML, you are going to like this....
==== The attached patch addresses these bugs, all of which have to do with export, viewing, and the like---ultimately, with the conversion routines. The patch introduces a new conversion flag, usetempdir, which forces the converter to do all its work in a temporary directory created under the lyx_tmpbuf directory. On export, this directory is copied to the directory in which the LyX file is contained. So, if you open /path/file.lyx and File>Export>Format, you will get a directory /path/file.format.conversion/ in which all the files generated by the converter will be found (e.g. the mess that htlatex generates ends up in /path/file.html.conversion/). If you're just viewing, however, you get $LYXTMPDIR/lyx_tmpbufN/format/, and of course that will get deleted when LyX exits (gracefully). As a result, the originaldir flag does not need to be used by any of our converters, and it may be redundant, though there's no harm leaving it, so far as I can see. As you will note, doing this involved adding a new signature to the Converters::convert() routine. I have not changed any of the other calls to this: these are in Importer.cpp, insets/InsetGraphics.cpp, and insets/ExternalSupport.cpp. At least some of these will need modifying before the patch is applied, probably all of them, as I suppose usetempdir could be set for importers and graphics converters and such. There are a few other clean-up type things to be done still, too, including fixing indentation, but I haven't done that yet as it would make the diff hard to read. Comments of course welcome. Will wait to commit for a bit, targeting for RC1?? Richard -- ================================================================== Richard G Heck, Jr Professor of Philosophy Brown University http://frege.brown.edu/heck/ ================================================================== Get my public key from http://sks.keyserver.penguin.de Hash: 0x1DE91F1E66FFBDEC Learn how to sign your email using Thunderbird and GnuPG at: http://dudu.dyn.2-h.org/nist/gpg-enigmail-howto
Index: src/Converter.h =================================================================== --- src/Converter.h (revision 18380) +++ src/Converter.h (working copy) @@ -59,6 +59,9 @@ bool original_dir; /// This converter needs the .aux files bool need_aux; + /// This converter should put its files in a separate temporary + /// directory + bool use_temp_dir; /// If the converter put the result in a directory, then result_dir /// is the name of the directory std::string result_dir; @@ -123,6 +126,14 @@ support::FileName const & orig_from, std::string const & from_format, std::string const & to_format, ErrorList & errorList, int conversionflags = none); + /// used_tmp_dir is a flag that signals whether our output files were put into + /// a temporary directory. Note also that to_file will be changed so that it points + /// at the converted file in this case. + bool convert(Buffer const * buffer, + support::FileName const & from_file, support::FileName & to_file, + support::FileName const & orig_from, bool & used_temp_dir, + std::string const & from_format, std::string const & to_format, + ErrorList & errorList, int conversionflags = none); /// void update(Formats const & formats); /// Index: src/Converter.cpp =================================================================== --- src/Converter.cpp (revision 18380) +++ src/Converter.cpp (working copy) @@ -31,7 +31,6 @@ #include "support/Path.h" #include "support/Systemcall.h" - namespace lyx { using support::addName; @@ -118,7 +117,8 @@ string const & c, string const & l) : from(f), to(t), command(c), flags(l), From(0), To(0), latex(false), xml(false), - original_dir(false), need_aux(false) + original_dir(false), need_aux(false), + use_temp_dir(false) {} @@ -135,6 +135,8 @@ xml = true; else if (flag_name == "originaldir") original_dir = true; + else if (flag_name == "usetempdir") + use_temp_dir = true; else if (flag_name == "needaux") need_aux = true; else if (flag_name == "resultdir") @@ -293,15 +295,30 @@ string const & from_format, string const & to_format, ErrorList & errorList, int conversionflags) { + FileName tmp_to_file = to_file; + bool trash; + return convert(buffer, from_file, tmp_to_file, orig_from, trash, + from_format, to_format, errorList, conversionflags); +} + + +bool Converters::convert(Buffer const * buffer, + FileName const & from_file, FileName & to_file, + FileName const & orig_from, bool & used_temp_dir, + string const & from_format, string const & to_format, + ErrorList & errorList, int conversionflags) +{ if (from_format == to_format) return move(from_format, from_file, to_file, false); - if ((conversionflags & try_cache) && - ConverterCache::get().inCache(orig_from, to_format)) - return ConverterCache::get().copy(orig_from, to_format, to_file); + used_temp_dir = false; Graph::EdgePath edgepath = getPath(from_format, to_format); if (edgepath.empty()) { + if ((conversionflags & try_cache) && + ConverterCache::get().inCache(orig_from, to_format) + ) + return ConverterCache::get().copy(orig_from, to_format, to_file); if (conversionflags & try_default) { // if no special converter defined, then we take the // default one from ImageMagic. @@ -336,8 +353,25 @@ from_ascii(from_format), from_ascii(to_format))); return false; } + + // At this point, we have a non-empty EdgePath (i.e., sequence + // of converters) to run. - // buffer is only invalid for importing, and then runparams is not + // set lastConv to the last converter in the chain + Converter const & lastConv = converterlist_[edgepath.back()]; + + //FIXME As things presently are, the cache routines aren't set up to + //cache more than one file. So we have to skip this when we're using + //the flags that indicate we're probably dealing with more than one + //file. For then only the main result file and none of the supporting + //files (eg, the CSS file in the case of htlatex) would be cached. + if ((conversionflags & try_cache) && + ConverterCache::get().inCache(orig_from, to_format) && + !lastConv.use_temp_dir && !lastConv.original_dir + ) + return ConverterCache::get().copy(orig_from, to_format, to_file); + + // buffer is invalid if we're importing, and then runparams is not // used anyway. OutputParams runparams(buffer ? &buffer->params().encoding() : 0); runparams.flavor = getFlavor(edgepath); @@ -346,7 +380,8 @@ // current directory, so we need to change the current directory. // This has the added benefit that all other files that may be // generated by the converter are deleted when LyX closes and do not - // clutter the real working directory. + // clutter the real working directory. If, however, the originaldir + // flag is set by a particular converter, we'll be switching there. string const path(onlyPath(from_file.absFilename())); // Prevent the compiler from optimizing away p FileName pp(path); @@ -377,11 +412,24 @@ // if input and output files are equal, we use a // temporary file as intermediary (JMarc) - FileName real_outfile; - if (outfile == infile) { + bool const needTempFile = (outfile == infile); + FileName real_outfile = outfile; + if (needTempFile) { real_outfile = infile; outfile = FileName(addName(buffer->temppath(), "tmpfile.out")); + } + // if we're using the original directory, we need to make sure + // outfile reflects that fact + if (conv.original_dir) { + outfile = FileName(addName(buffer->filePath(), + onlyFilename(outfile.toFilesystemEncoding()))); } + // and if we're using a temporary directory, same deal.... + else if (conv.use_temp_dir) { + outfile = FileName(addName( + addName(buffer->temppath(), to_format), + onlyFilename(outfile.toFilesystemEncoding()))); + } if (conv.latex) { run_latex = true; @@ -389,8 +437,7 @@ LYXERR(Debug::FILES) << "Running " << command << endl; if (!runLaTeX(*buffer, command, runparams, errorList)) return false; - } else { - if (conv.need_aux && !run_latex + } else if (conv.need_aux && !run_latex && !latex_command_.empty()) { LYXERR(Debug::FILES) << "Running " << latex_command_ @@ -399,13 +446,15 @@ } // FIXME UNICODE - string const infile2 = (conv.original_dir) - ? infile.absFilename() : to_utf8(makeRelPath(from_utf8(infile.absFilename()), - from_utf8(path))); - string const outfile2 = (conv.original_dir) - ? outfile.absFilename() : to_utf8(makeRelPath(from_utf8(outfile.absFilename()), - from_utf8(path))); - + string const infile2 = (conv.original_dir || conv.use_temp_dir) + ? infile.absFilename() : + to_utf8(makeRelPath(from_utf8(infile.absFilename()), + from_utf8(path))); + string const outfile2 = (conv.original_dir || conv.use_temp_dir) + ? outfile.absFilename() : + to_utf8(makeRelPath(from_utf8(outfile.absFilename()), + from_utf8(path))); + string command = conv.command; command = subst(command, token_from, quoteName(infile2)); command = subst(command, token_base, quoteName(from_base)); @@ -436,11 +485,22 @@ support::Path p(path); res = one.startscript(type, to_filesystem8bit(from_utf8(command))); + } else if (conv.use_temp_dir) { + FileName path(addName(buffer->temppath(), to_format)); + if (!isDirWriteable(path) && !createDirectory(path, 0777)) { + Alert::error(_("Directory error"), + _("Unable to create temporary directory.")); + return false; + } + support::Path p(path); + res = one.startscript(type, + to_filesystem8bit(from_utf8(command))); } else res = one.startscript(type, to_filesystem8bit(from_utf8(command))); - if (!real_outfile.empty()) { + if (needTempFile) { + // move temporary file to requested location Mover const & mover = getMover(conv.to); if (!mover.rename(outfile, real_outfile)) res = -1; @@ -449,9 +509,12 @@ << "renaming file " << outfile << " to " << real_outfile << endl; - // Finally, don't forget to tell any future - // converters to use the renamed file... + // make sure the next converter knows what file to use outfile = real_outfile; + } else { + //check if the output file exists + if(!isFileReadable(outfile)) + res = -1; } if (!conv.parselog.empty()) { @@ -480,21 +543,20 @@ return false; } } - } + // all the converters have now been run - Converter const & conv = converterlist_[edgepath.back()]; - if (conv.To->dummy()) + if (lastConv.To->dummy()) return true; - if (!conv.result_dir.empty()) { + if (!lastConv.result_dir.empty()) { // The converter has put the file(s) in a directory. // In this case we ignore the given to_file. if (from_base != to_base) { - string const from = subst(conv.result_dir, + string const from = subst(lastConv.result_dir, token_base, from_base); - string const to = subst(conv.result_dir, + string const to = subst(lastConv.result_dir, token_base, to_base); - Mover const & mover = getMover(conv.from); + Mover const & mover = getMover(lastConv.from); if (!mover.rename(FileName(from), FileName(to))) { Alert::error(_("Cannot convert file"), bformat(_("Could not move a temporary directory from %1$s to %2$s."), @@ -503,11 +565,19 @@ } } return true; - } else { - if (conversionflags & try_cache) - ConverterCache::get().add(orig_from, to_format, outfile); - return move(conv.to, outfile, to_file, conv.latex); } + // else... + // if the last converter created its own temporary directory, then + // the files can stay there. + if (lastConv.use_temp_dir) { + to_file = outfile; + used_temp_dir = true; + return true; + } // note that we skip the cache in this case + // else... + if ((conversionflags & try_cache) && !lastConv.original_dir) + ConverterCache::get().add(orig_from, to_format, outfile); + return move(lastConv.to, outfile, to_file, lastConv.latex); } Index: src/Exporter.cpp =================================================================== --- src/Exporter.cpp (revision 18380) +++ src/Exporter.cpp (working copy) @@ -213,19 +213,53 @@ string const error_type = (format == "program")? "Build" : bufferFormat(*buffer); string const ext = formats.extension(format); - FileName const tmp_result_file(changeExtension(filename, ext)); + bool used_temp_dir = false; + FileName tmp_result_file(changeExtension(filename, ext)); bool const success = theConverters().convert(buffer, FileName(filename), - tmp_result_file, FileName(buffer->fileName()), backend_format, format, - buffer->errorList(error_type)); + tmp_result_file, FileName(buffer->fileName()), used_temp_dir, backend_format, + format, buffer->errorList(error_type)); // Emit the signal to show the error list. if (format != backend_format) buffer->errors(error_type); if (!success) return false; - if (put_in_tempdir) + if (put_in_tempdir) { result_file = tmp_result_file.absFilename(); - else { + } else if (used_temp_dir) { + FileName const temp_dir = + FileName(onlyPath(tmp_result_file.toFilesystemEncoding())); + string const new_dir = + addName(onlyPath(buffer->fileName()), + changeExtension(buffer->getLatexName(true), "") + + "." + format + ".conversion"); + FileName newDir = FileName(new_dir); + //FIXME Should be put in a copyDirectory() routine. + //FIXME + //if (isDirWriteable) + // get permission possibly to overwrite its contents. + if (!isDirWriteable(newDir) && !createDirectory(newDir, 0777)) { + Alert::error(_("Directory error"), + _("Unable to create destination directory." + "Output files are in LyX temporary directory.")); + return false; + } + vector<FileName> const files = dirList(temp_dir); + for (vector<FileName>::const_iterator it = files.begin(); + it != files.end(); ++it) + { + string const fromFile = it->absFilename(); + string const toFile = addName(new_dir, onlyFilename(fromFile)); + try { + fs::copy_file(fromFile, toFile); + } catch (fs::filesystem_error & e) { + Alert::error(_("File copy error"), + _("Unable to copy files." + "Output files are in LyX temporary directory.")); + return false; + } + } + } else { result_file = changeExtension(buffer->fileName(), ext); // We need to copy referenced files (e. g. included graphics // if format == "dvi") to the result dir. @@ -253,7 +287,9 @@ formats.prettyName(format), makeDisplayPath(result_file))); } else { - // This must be a dummy converter like fax (bug 1888) + // This is either a dummy converter like fax (bug 1888) + // or the result of a converter chain that ended with + // one whose originaldir flag was set. buffer->message(bformat(_("Document exported as %1$s"), formats.prettyName(format))); } Index: lib/configure.py =================================================================== --- lib/configure.py (revision 18396) +++ lib/configure.py (working copy) @@ -348,7 +348,7 @@ rc_entry = [ r'\converter word latex "%%" ""' ]) # checkProg('a LaTeX -> MS Word converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"], - rc_entry = [ r'\converter latex wordhtml "%%" "originaldir,needaux"' ]) + rc_entry = [ r'\converter latex wordhtml "%%" "usetempdir,needaux"' ]) # checkProg('an OpenOffice.org -> LaTeX converter', ['w2l -clean $$i'], rc_entry = [ r'\converter sxw latex "%%" ""' ]) @@ -431,7 +431,7 @@ # checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'tth -t -e2 -L$$b < $$i > $$o', \ 'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'], - rc_entry = [ r'\converter latex html "%%" "originaldir,needaux"' ]) + rc_entry = [ r'\converter latex html "%%" "usetempdir,needaux"' ]) # path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond']) if (lilypond != ''):