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 != ''):

Reply via email to