X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fsupport%2Fos.cpp;h=616b9c6936d4a16594f239fbb2dc1d2332db1358;hb=cf14e814124ccbc8155fa1dde98d03be319c0e87;hp=8eea49370ae7d125bfe033d44cbae497086c89af;hpb=586890f09ef6ee20ee7f1ed709119774b86cbe24;p=lyx.git diff --git a/src/support/os.cpp b/src/support/os.cpp index 8eea49370a..616b9c6936 100644 --- a/src/support/os.cpp +++ b/src/support/os.cpp @@ -11,9 +11,15 @@ #include +#ifdef _WIN32 +# define _WIN32_WINNT 0x0600 +#endif + +#include "support/convert.h" #include "support/debug.h" #include "support/filetools.h" #include "support/qstring_helpers.h" +#include "support/regex.h" #include @@ -38,68 +44,143 @@ namespace lyx { namespace support { namespace os { -static string const python23(string const & binary, bool verbose = false) +int timeout_min() +{ + 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 + " -V 2>&1"); - if (out.first < 0 || - (!prefixIs(out.second, "Python 2") && - !prefixIs(out.second, "Python 3"))) + 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(sm.str(1)); + int minor = convert(sm.str(2)); + if((major == 2 && minor < 7) || (major == 3 && minor < 5)) return string(); if (verbose) - lyxerr << "Found " << out.second << "\n"; - return binary; + lyxerr << "Found Python " << out.second << "\n"; + // Add the -tt switch so that mixed tab/whitespace + // indentation is an error + return binary + " -tt"; } -int timeout_min() +static string const find_python_binary() { - return 3; + // 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/ + +#ifdef _WIN32 + // Check through python launcher whether python 3 is + // installed on computer. + string command = python23_call("py -3"); +#else + // Check whether python3 in PATH is the right one. + string command = python23_call("python3"); +#endif // _WIN32 + if (!command.empty()) + return command; + +#ifndef _WIN32 + // 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 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 bin2 : list) { + string const binary = "\"" + addName(localdir, + bin2.toLocal8Bit().constData()) + "\""; + command = python23_call(binary, true); + if (!command.empty()) + return command; + } + } +#endif // !_WIN32 + + // python 3 was not found let us look for python 2 +#ifdef _WIN32 + command = python23_call("py -2"); +#else + command = python23_call("python2"); +#endif // _WIN32 + if (!command.empty()) + return command; + +#ifdef _WIN32 + // python launcher is not installed, let cmd auto check + // PATH for a python.exe + command = python23_call("python"); + if (!command.empty()) + return command; + + //failed, prepare to search PATH manually + vector const path = getEnvPath("PATH"); + lyxerr << "Manually looking for python in PATH ...\n"; + QString const exeName = "python*"; +#else + // 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"; + QString const exeName = "python2*"; +#endif // _WIN32 + + 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(exeName)); + for (auto bin2 : list) { + string const binary = "\"" + addName(localdir, + bin2.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) { - // Check whether the first python in PATH is the right one. - static string command = python23("python -tt"); + static string command = find_python_binary(); // FIXME THREAD if (reset) { - command = python23("python -tt"); - } - - if (command.empty()) { - // It was not, so check whether we can find it elsewhere in - // PATH, maybe with some suffix appended. - vector const path = getEnvPath("PATH"); - vector::const_iterator it = path.begin(); - vector::const_iterator const end = path.end(); - lyxerr << "Looking for python v2.x or 3.x ...\n"; - for (; it != end; ++it) { - QString const dir = toqstr(*it); - string const localdir = dir.toLocal8Bit().constData(); - QDir qdir(dir); - qdir.setFilter(QDir::Files | QDir::Executable); - QStringList list = qdir.entryList(QStringList("python*")); - for (int i = 0; i < list.size() && command.empty(); ++i) { - string const binary = addName(localdir, - list.at(i).toLocal8Bit().constData()); - command = python23(binary, true); - } - } - - // Default to "python" if no usable binary was found. - if (command.empty()) { - lyxerr << "Warning: No python v2.x or 3.x binary found.\n"; - command = "python"; - } - - // Add the -tt switch so that mixed tab/whitespace - // indentation is an error - command += " -tt"; + command = find_python_binary(); } return command; }