]> git.lyx.org Git - lyx.git/blobdiff - src/graphics/GraphicsConverter.C
* lib/Makefile.am s/convertDefault.sh/convertDefault.py/
[lyx.git] / src / graphics / GraphicsConverter.C
index 23a552084def640ade60602f691c27c816185024..941aeb2a0ff1c531b28fb20c7b6c4c0d94b3fdfb 100644 (file)
 
 #include "support/filetools.h"
 #include "support/forkedcallqueue.h"
-#include "support/tostr.h"
+#include "support/convert.h"
 #include "support/lstrings.h"
 #include "support/lyxlib.h"
 
 #include <boost/bind.hpp>
 
-#include "support/std_sstream.h"
+#include <sstream>
 #include <fstream>
 
 namespace support = lyx::support;
 
-using support::ChangeExtension;
+using support::changeExtension;
 using support::Forkedcall;
 using support::ForkedCallQueue;
-using support::LibFileSearch;
-using support::LibScriptSearch;
-using support::OnlyPath;
-using support::OnlyFilename;
-using support::QuoteName;
+using support::libFileSearch;
+using support::libScriptSearch;
+using support::onlyPath;
+using support::onlyFilename;
+using support::quoteName;
 using support::subst;
 using support::tempName;
 using support::unlink;
@@ -44,12 +44,14 @@ using support::unlink;
 using std::endl;
 using std::ostream;
 using std::ostringstream;
+using std::string;
 
 
 namespace lyx {
 namespace graphics {
 
-struct Converter::Impl : public boost::signals::trackable {
+class Converter::Impl : public boost::signals::trackable {
+public:
        ///
        Impl(string const &, string const &, string const &, string const &);
 
@@ -66,7 +68,7 @@ struct Converter::Impl : public boost::signals::trackable {
        /** At the end of the conversion process inform the outside world
         *  by emitting a signal.
         */
-       typedef boost::signal1<void, bool> SignalType;
+       typedef boost::signal<void(bool)> SignalType;
        ///
        SignalType finishedConversion;
 
@@ -159,45 +161,62 @@ Converter::Impl::Impl(string const & from_file,   string const & to_file_base,
 
        // The conversion commands are stored in a stringstream
        ostringstream script;
-       script << "#!/bin/sh\n";
+       script << "#!/usr/bin/env python\n"
+                  << "import os, sys\n\n"
+                  << "def unlinkNoThrow(file):\n"
+                  << "  ''' remove a file, do not throw if an error occurs '''\n"
+                  << "  try:\n"
+                  << "    os.unlink(file)\n"
+                  << "  except:\n"
+                  << "    pass\n\n";
+
        bool const success = build_script(from_file, to_file_base,
                                          from_format, to_format, script);
 
        if (!success) {
                script_command_ =
-                       "sh " + LibFileSearch("scripts", "convertDefault.sh") +
-                       ' ' + from_format + ':' + from_file + ' ' +
-                       to_format + ':' + to_file_;
+                       "python " +
+                       quoteName(libFileSearch("scripts", "convertDefault.py")) +
+                       ' ' +
+                       quoteName((from_format.empty() ? "" : from_format + ':') + from_file) +
+                       ' ' +
+                       quoteName(to_format + ':' + to_file_);
 
                lyxerr[Debug::GRAPHICS]
-                       << "\tNo converter defined! I use convertDefault.sh\n\t"
+                       << "\tNo converter defined! I use convertDefault.py\n\t"
                        << script_command_ << endl;
 
        } else {
 
                lyxerr[Debug::GRAPHICS] << "\tConversion script:"
                        << "\n--------------------------------------\n"
-                       << STRCONV(script.str())
+                       << script.str()
                        << "\n--------------------------------------\n";
 
                // Output the script to file.
                static int counter = 0;
-               script_file_ = OnlyPath(to_file_base) + "lyxconvert" +
-                       tostr(counter++) + ".sh";
+               script_file_ = onlyPath(to_file_base) + "lyxconvert" +
+                       convert<string>(counter++) + ".py";
 
                std::ofstream fs(script_file_.c_str());
-               if (!fs.good())
+               if (!fs.good()) {
+                       lyxerr << "Unable to write the conversion script to \""
+                              << script_file_ << '\n'
+                              << "Please check your directory permissions."
+                              << std::endl;
                        return;
+               }
 
-               fs << STRCONV(script.str());
+               fs << script.str();
                fs.close();
 
                // The command needed to run the conversion process
                // We create a dummy command for ease of understanding of the
                // list of forked processes.
                // Note: 'sh ' is absolutely essential, or execvp will fail.
-               script_command_ = "sh " + script_file_ + ' ' +
-                       OnlyFilename(from_file) + ' ' + to_format;
+               script_command_ = "python " + quoteName(script_file_) + ' ' +
+                       quoteName(onlyFilename(from_file)) + ' ' +
+                       quoteName(to_format);
        }
        // All is ready to go
        valid_process_ = true;
@@ -248,21 +267,66 @@ string const move_file(string const & from_file, string const & to_file)
                return string();
 
        ostringstream command;
-       command << "fromfile=" << from_file << "\n"
-               << "tofile="   << to_file << "\n\n"
-               << "'mv' -f ${fromfile} ${tofile} ||\n"
-               << "{\n"
-               << "\t'cp' -f ${fromfile} ${tofile} ||\n"
-               << "\t{\n"
-               << "\t\texit 1\n"
-               << "\t}\n"
-               << "\t'rm' -f ${fromfile}\n"
-               << "}\n";
-
-       return STRCONV(command.str());
+       command << "fromfile = " << from_file << "\n"
+               << "tofile = "   << to_file << "\n\n"
+               << "try:\n"
+               << "  os.rename(fromfile, tofile)\n"
+               << "except:\n"
+               << "  import shutil\n"
+               << "  try:\n"
+               << "    shutil.copy(fromfile, tofile)\n"
+               << "  except:\n"
+               << "    sys.exit(1)\n"
+               << "  unlinkNoThrow(fromfile)\n";
+
+       return command.str();
 }
 
 
+/*
+A typical script looks like:
+
+#!/usr/bin/env python
+import os, sys
+
+def unlinkNoThrow(file):
+  ''' remove a file, do not throw if error occurs '''
+  try:
+    os.unlink(file)
+  except:
+    pass
+
+infile = '/home/username/Figure3a.eps'
+infile_base = '/home/username/Figure3a'
+outfile = '/tmp/lyx_tmpdir12992hUwBqt/gconvert0129929eUBPm.pdf'
+
+if os.system(r'epstopdf ' + '"' + infile + '"' + ' --output ' + '"' + outfile + '"' + '') != 0:
+  unlinkNoThrow(outfile)
+  sys.exit(1)
+
+if not os.path.isfile(outfile):
+  if os.path.isfile(outfile + '.0'):
+    os.rename(outfile + '.0', outfile)
+    import glob
+    for file in glob.glob(outfile + '.?'):
+      unlinkNoThrow(file)
+  else:
+    sys.exit(1)
+
+fromfile = outfile
+tofile = '/tmp/lyx_tmpdir12992hUwBqt/Figure3a129927ByaCl.ppm'
+
+try:
+  os.rename(fromfile, tofile)
+except:
+  import shutil
+  try:
+    shutil.copy(fromfile, tofile)
+  except:
+    sys.exit(1)
+  unlinkNoThrow(fromfile)
+
+*/
 bool build_script(string const & from_file,
                  string const & to_file_base,
                  string const & from_format,
@@ -272,13 +336,16 @@ bool build_script(string const & from_file,
        lyxerr[Debug::GRAPHICS] << "build_script ... ";
        typedef Converters::EdgePath EdgePath;
 
+       if (from_format.empty())
+               return false;
+
        // we do not use ChangeExtension because this is a basename
        // which may nevertheless contain a '.'
        string const to_file = to_file_base + '.'
                + formats.extension(to_format);
 
        if (from_format == to_format) {
-               script << move_file(QuoteName(from_file), QuoteName(to_file));
+               script << move_file(quoteName(from_file), quoteName(to_file));
                lyxerr[Debug::GRAPHICS] << "ready (from == to)" << endl;
                return true;
        }
@@ -293,7 +360,7 @@ bool build_script(string const & from_file,
        // Create a temporary base file-name for all intermediate steps.
        // Remember to remove the temp file because we only want the name...
        static int counter = 0;
-       string const tmp = "gconvert" + tostr(counter++);
+       string const tmp = "gconvert" + convert<string>(counter++);
        string const to_base = tempName(string(), tmp);
        unlink(to_base);
 
@@ -313,52 +380,50 @@ bool build_script(string const & from_file,
 
                // Build the conversion command
                string const infile      = outfile;
-               string const infile_base = ChangeExtension(infile, string());
-               outfile = ChangeExtension(to_base, conv.To->extension());
+               string const infile_base = changeExtension(infile, string());
+               outfile = changeExtension(to_base, conv.To->extension());
 
                // Store these names in the shell script
-               script << "infile="      << QuoteName(infile) << '\n'
-                      << "infile_base=" << QuoteName(infile_base) << '\n'
-                      << "outfile="     << QuoteName(outfile) << '\n';
+               script << "infile = "      << quoteName(infile) << '\n'
+                      << "infile_base = " << quoteName(infile_base) << '\n'
+                      << "outfile = "     << quoteName(outfile) << '\n';
 
                string command = conv.command;
-               command = subst(command, token_from, "${infile}");
-               command = subst(command, token_base, "${infile_base}");
-               command = subst(command, token_to,   "${outfile}");
-               command = LibScriptSearch(command);
+               command = subst(command, token_from, "' + '\"' + infile + '\"' + '");
+               command = subst(command, token_base, "' + '\"' + infile_base + '\"' + '");
+               command = subst(command, token_to,   "' + '\"' + outfile + '\"' + '");
+               command = libScriptSearch(command);
 
                // Store in the shell script
-               script << "\n" << command << " ||\n";
+               script << "\nif os.system(r'" << command << "') != 0:\n";
 
                // Test that this was successful. If not, remove
                // ${outfile} and exit the shell script
-               script << "{\n"
-                      << "\t'rm' -f ${outfile}\n"
-                      << "\texit 1\n"
-                      << "}\n\n";
+               script << "  unlinkNoThrow(outfile)\n"
+                      << "  sys.exit(1)\n\n";
 
                // Test that the outfile exists.
                // ImageMagick's convert will often create ${outfile}.0,
                // ${outfile}.1.
                // If this occurs, move ${outfile}.0 to ${outfile}
-               // and delete ${outfile}.?
-               script << "if [ ! -f ${outfile} ]; then\n"
-                      << "\tif [ -f ${outfile}.0 ]; then\n"
-                      << "\t\t'mv' -f ${outfile}.0 ${outfile}\n"
-                      << "\t\t'rm' -f ${outfile}.?\n"
-                      << "\telse\n"
-                      << "\t\texit 1\n"
-                      << "\tfi\n"
-                      << "fi\n\n";
+               // and delete ${outfile}.? (ignore errors)
+               script << "if not os.path.isfile(outfile):\n"
+                      << "  if os.path.isfile(outfile + '.0'):\n"
+                      << "    os.rename(outfile + '.0', outfile)\n"
+                          << "    import glob\n"
+                      << "    for file in glob.glob(outfile + '.?'):\n"
+                          << "      unlinkNoThrow(file)\n"
+                      << "  else:\n"
+                      << "    sys.exit(1)\n\n";
 
                // Delete the infile, if it isn't the original, from_file.
                if (infile != from_file) {
-                       script << "'rm' -f ${infile}\n\n";
+                       script << "unlinkNoThrow(infile)\n\n";
                }
        }
 
        // Move the final outfile to to_file
-       script << move_file("${outfile}", QuoteName(to_file));
+       script << move_file("outfile", quoteName(to_file));
        lyxerr[Debug::GRAPHICS] << "ready!" << endl;
 
        return true;