]> git.lyx.org Git - lyx.git/blob - src/support/os.cpp
Change python run time detection to privilege python 3 over python 2.
[lyx.git] / src / support / os.cpp
1 /**
2  * \file os.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Ruurd A. Reitsma
7  * \author Enrico Forestieri
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "support/convert.h"
15 #include "support/debug.h"
16 #include "support/filetools.h"
17 #include "support/qstring_helpers.h"
18 #include "support/regex.h"
19
20 #include <QDir>
21
22 #if defined(__CYGWIN__)
23 #include "support/os_cygwin.cpp"
24 #elif defined(_WIN32)
25 #include "support/os_win32.cpp"
26 #else
27 #include "support/os_unix.cpp"
28 #endif
29
30 // Static assert to break compilation on platforms where
31 // int/unsigned int is not 4 bytes. Added to make sure that
32 // e.g., the author hash is always 32-bit.
33 template<bool Condition> struct static_assert_helper;
34 template <> struct static_assert_helper<true> {};
35 enum {
36         dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
37 };
38
39 namespace lyx {
40 namespace support {
41 namespace os {
42
43 static string const python23(string const & binary, bool verbose = false)
44 {
45         const string version_info = " -c 'from __future__ import print_function;import sys; print(sys.version_info[:2], end=\"\")'";
46         static regex const python_reg("\\((\\d*), (\\d*)\\)");
47         if (verbose)
48                 lyxerr << "Examining " << binary << "\n";
49
50         // Check whether this is a python 2 or 3 binary.
51         cmd_ret const out = runCommand(binary + version_info);
52
53         smatch sm;
54         if (out.first < 0 || !regex_match(out.second, sm, python_reg))
55                 return string();
56
57         int major = convert<int>(sm.str(1));
58         int minor = convert<int>(sm.str(2));
59         if((major == 2 and minor < 7) or (major == 3 and minor < 4))
60                 return string();
61
62         if (verbose)
63                 lyxerr << "Found Python " << out.second << "\n";
64         return binary;
65 }
66
67
68 int timeout_min()
69 {
70         return 3;
71 }
72
73
74 string const python(bool reset)
75 {
76         // Check whether python3 in PATH is the right one.
77         static string command = python23("python3");
78         // FIXME THREAD
79         if (reset) {
80                 command = python23("python3");
81         }
82
83         // python3 does not exists, let us try python3.x
84         if (command.empty()) {
85                 // It was not, so check whether we can find it elsewhere in
86                 // PATH, maybe with some suffix appended.
87                 vector<string> const path = getEnvPath("PATH");
88                 lyxerr << "Looking for python 3.x ...\n";
89                 for (auto bin: path) {
90                         QString const dir = toqstr(bin);
91                         string const localdir = dir.toLocal8Bit().constData();
92                         QDir qdir(dir);
93                         qdir.setFilter(QDir::Files | QDir::Executable);
94                         QStringList list = qdir.entryList(QStringList("python3*"));
95                         for (int i = 0; i < list.size() && command.empty(); ++i) {
96                                 string const binary = addName(localdir,
97                                         list.at(i).toLocal8Bit().constData());
98                                 command = python23(binary, true);
99                         }
100                 }
101
102         }
103         // python 3 not found let us look for python 2
104         if (command.empty())
105                 command = python23("python2");
106
107         // python2 does not exists, let us try python2.x
108         if (command.empty()) {
109                 // It was not, so check whether we can find it elsewhere in
110                 // PATH, maybe with some suffix appended.
111                 vector<string> const path = getEnvPath("PATH");
112                 lyxerr << "Looking for python 3.x ...\n";
113                 for (auto bin: path) {
114                         QString const dir = toqstr(bin);
115                         string const localdir = dir.toLocal8Bit().constData();
116                         QDir qdir(dir);
117                         qdir.setFilter(QDir::Files | QDir::Executable);
118                         QStringList list = qdir.entryList(QStringList("python2*"));
119                         for (int i = 0; i < list.size() && command.empty(); ++i) {
120                                 string const binary = addName(localdir,
121                                         list.at(i).toLocal8Bit().constData());
122                                 command = python23(binary, true);
123                         }
124                 }
125
126         }
127
128         // Default to "python" if no usable binary was found.
129         // If this happens all hope is lost that there is a sane system
130         if (command.empty()) {
131                 lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
132                 command = "python";
133         }
134
135         // Add the -tt switch so that mixed tab/whitespace
136         // indentation is an error
137         command += " -tt";
138         return command;
139 }
140
141 } // namespace os
142 } // namespace support
143 } // namespace lyx