]> git.lyx.org Git - lyx.git/blob - src/support/os.cpp
Move python related functions together to make it easy to read the code.
[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 int timeout_min()
44 {
45         return 3;
46 }
47
48
49 static string const python23(string const & binary, bool verbose = false)
50 {
51         const string version_info = " -c 'from __future__ import print_function;import sys; print(sys.version_info[:2], end=\"\")'";
52         static regex const python_reg("\\((\\d*), (\\d*)\\)");
53         if (verbose)
54                 lyxerr << "Examining " << binary << "\n";
55
56         // Check whether this is a python 2 or 3 binary.
57         cmd_ret const out = runCommand(binary + version_info);
58
59         smatch sm;
60         if (out.first < 0 || !regex_match(out.second, sm, python_reg))
61                 return string();
62
63         int major = convert<int>(sm.str(1));
64         int minor = convert<int>(sm.str(2));
65         if((major == 2 && minor < 7) || (major == 3 && minor < 4))
66                 return string();
67
68         if (verbose)
69                 lyxerr << "Found Python " << out.second << "\n";
70         return binary;
71 }
72
73
74 string const python(bool reset)
75 {
76         // This function takes inspiration from PEP 394 and PEP 397
77         // PEP 394 -- The "python" Command on Unix-Like Systems
78         // https://www.python.org/dev/peps/pep-0394/
79         // PEP 397 -- Python launcher for Windows
80         // https://www.python.org/dev/peps/pep-0397/
81
82         // Check whether python3 in PATH is the right one.
83         static string command = python23("python3");
84         // FIXME THREAD
85         if (reset) {
86                 command = python23("python3");
87         }
88
89         // python3 does not exists, let us try to find python3.x in PATH
90         // the search is probably broader than required
91         // but we are trying hard to find a valid python binary
92         if (command.empty()) {
93                 vector<string> const path = getEnvPath("PATH");
94                 lyxerr << "Looking for python 3.x ...\n";
95                 for (auto bin: path) {
96                         QString const dir = toqstr(bin);
97                         string const localdir = dir.toLocal8Bit().constData();
98                         QDir qdir(dir);
99                         qdir.setFilter(QDir::Files | QDir::Executable);
100                         QStringList list = qdir.entryList(QStringList("python3*"));
101                         for (int i = 0; i < list.size() && command.empty(); ++i) {
102                                 string const binary = addName(localdir,
103                                         list.at(i).toLocal8Bit().constData());
104                                 command = python23(binary, true);
105                         }
106                 }
107
108         }
109         // python 3 was not found let us look for python 2
110         if (command.empty())
111                 command = python23("python2");
112
113         // python2 does not exists, let us try to find python2.x in PATH
114         // the search is probably broader than required
115         // but we are trying hard to find a valid python binary
116         if (command.empty()) {
117                 vector<string> const path = getEnvPath("PATH");
118                 lyxerr << "Looking for python 2.x ...\n";
119                 for (auto bin: path) {
120                         QString const dir = toqstr(bin);
121                         string const localdir = dir.toLocal8Bit().constData();
122                         QDir qdir(dir);
123                         qdir.setFilter(QDir::Files | QDir::Executable);
124                         QStringList list = qdir.entryList(QStringList("python2*"));
125                         for (int i = 0; i < list.size() && command.empty(); ++i) {
126                                 string const binary = addName(localdir,
127                                         list.at(i).toLocal8Bit().constData());
128                                 command = python23(binary, true);
129                         }
130                 }
131
132         }
133
134         // Default to "python" if no usable binary was found.
135         // If this happens all hope is lost that this is a sane system
136         if (command.empty()) {
137                 lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
138                 command = "python";
139         }
140
141         // Add the -tt switch so that mixed tab/whitespace
142         // indentation is an error
143         command += " -tt";
144         return command;
145 }
146
147 } // namespace os
148 } // namespace support
149 } // namespace lyx