]> git.lyx.org Git - lyx.git/blobdiff - src/support/os.cpp
Update some files
[lyx.git] / src / support / os.cpp
index 6984d2c7480fbfd43fe0079716d7eab4252a370d..ab9d4159a6cc8180864e760f330af3fc95bbb5d7 100644 (file)
@@ -4,13 +4,22 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Ruurd A. Reitsma
+ * \author Enrico Forestieri
  *
  * Full author contact details are available in file CREDITS.
  */
 
 #include <config.h>
 
-#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+#include "support/convert.h"
+#include "support/debug.h"
+#include "support/filetools.h"
+#include "support/qstring_helpers.h"
+#include "support/regex.h"
+
+#include <QDir>
+
+#if defined(__CYGWIN__)
 #include "support/os_cygwin.cpp"
 #elif defined(_WIN32)
 #include "support/os_win32.cpp"
 #include "support/os_unix.cpp"
 #endif
 
+// Static assert to break compilation on platforms where
+// int/unsigned int is not 4 bytes. Added to make sure that
+// e.g., the author hash is always 32-bit.
+template<bool Condition> struct static_assert_helper;
+template <> struct static_assert_helper<true> {};
+enum {
+       dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
+};
+
 namespace lyx {
 namespace support {
 namespace os {
 
-string const python()
+int timeout_min()
 {
-       // Use the -tt switch so that mixed tab/whitespace indentation is
-       // an error
-       static string const command("python -tt");
-       return command;
+       return 3;
 }
 
+
+static string const python23_call(string const & binary, bool verbose = false)
+{
+       const string version_info = " -c 'from __future__ import print_function;import sys; print(sys.version_info[:2], end=\"\")'";
+       // Default to "python" if no binary is given.
+       if (binary.empty())
+               return "python -tt";
+
+       if (verbose)
+               lyxerr << "Examining " << binary << "\n";
+       // Check whether this is a python 2 or 3 binary.
+       cmd_ret const out = runCommand(binary + version_info);
+
+       smatch sm;
+       try {
+               static regex const python_reg("\\((\\d*), (\\d*)\\)");
+               if (out.first < 0 || !regex_match(out.second, sm, python_reg))
+                       return string();
+       } catch(regex_error const & /*e*/) {
+               LYXERR0("Regex error! This should not happen.");
+               return string();
+       }
+
+       int major = convert<int>(sm.str(1));
+       int minor = convert<int>(sm.str(2));
+       if((major == 2 && minor < 7) || (major == 3 && minor < 5))
+               return string();
+
+       if (verbose)
+               lyxerr << "Found Python " << out.second << "\n";
+       // Add the -tt switch so that mixed tab/whitespace
+       // indentation is an error
+       return binary + " -tt";
 }
+
+
+static string const find_python_binary()
+{
+       // This function takes inspiration from PEP 394 and PEP 397
+       // PEP 394 -- The "python" Command on Unix-Like Systems
+       // https://www.python.org/dev/peps/pep-0394/
+       // PEP 397 -- Python launcher for Windows
+       // https://www.python.org/dev/peps/pep-0397/
+
+       // Check whether python3 in PATH is the right one.
+       string command = python23_call("python3");
+       if (!command.empty())
+               return command;
+
+       // python3 does not exists, let us try to find python3.x in PATH
+       // the search is probably broader than required
+       // but we are trying hard to find a valid python binary
+       vector<string> const path = getEnvPath("PATH");
+       lyxerr << "Looking for python 3.x ...\n";
+       for (auto bin: path) {
+               QString const dir = toqstr(bin);
+               string const localdir = dir.toLocal8Bit().constData();
+               QDir qdir(dir);
+               qdir.setFilter(QDir::Files | QDir::Executable);
+               QStringList list = qdir.entryList(QStringList("python3*"));
+               for (auto bin: list) {
+                       string const binary = addName(localdir,
+                               bin.toLocal8Bit().constData());
+                       command = python23_call(binary, true);
+                       if (!command.empty())
+                               return command;
+               }
+       }
+
+       // python 3 was not found let us look for python 2
+       command = python23_call("python2");
+       if (!command.empty())
+               return command;
+
+       // python2 does not exists, let us try to find python2.x in PATH
+       // the search is probably broader than required
+       // but we are trying hard to find a valid python binary
+       lyxerr << "Looking for python 2.x ...\n";
+       for (auto bin: path) {
+               QString const dir = toqstr(bin);
+               string const localdir = dir.toLocal8Bit().constData();
+               QDir qdir(dir);
+               qdir.setFilter(QDir::Files | QDir::Executable);
+               QStringList list = qdir.entryList(QStringList("python2*"));
+               for (auto bin: list) {
+                       string const binary = addName(localdir,
+                               bin.toLocal8Bit().constData());
+                       command = python23_call(binary, true);
+                       if (!command.empty())
+                               return command;
+               }
+       }
+
+       // If this happens all hope is lost that this is a sane system
+       lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
+       return python23_call("");
 }
+
+
+string const python(bool reset)
+{
+       static string command = find_python_binary();
+       // FIXME THREAD
+       if (reset) {
+               command = find_python_binary();
+       }
+       return command;
 }
+
+} // namespace os
+} // namespace support
+} // namespace lyx