]> git.lyx.org Git - lyx.git/blob - src/support/os.cpp
Correct comment
[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 #ifdef _WIN32
15 # define _WIN32_WINNT 0x0600
16 #endif
17
18 #include "support/convert.h"
19 #include "support/debug.h"
20 #include "support/filetools.h"
21 #include "support/qstring_helpers.h"
22 #include "support/regex.h"
23
24 #include <QDir>
25
26 #if defined(__CYGWIN__)
27 #include "support/os_cygwin.cpp"
28 #elif defined(_WIN32)
29 #include "support/os_win32.cpp"
30 #else
31 #include "support/os_unix.cpp"
32 #endif
33
34 // Static assert to break compilation on platforms where
35 // int/unsigned int is not 4 bytes. Added to make sure that
36 // e.g., the author hash is always 32-bit.
37 template<bool Condition> struct static_assert_helper;
38 template <> struct static_assert_helper<true> {};
39 enum {
40         dummy = sizeof(static_assert_helper<sizeof(int) == 4>)
41 };
42
43 namespace lyx {
44 namespace support {
45 namespace os {
46
47 int timeout_min()
48 {
49         return 3;
50 }
51
52
53 static string const python23_call(string const & binary, bool verbose = false)
54 {
55         const string version_info = " -c \"from __future__ import print_function;import sys; print(sys.version_info[:2], end=\\\"\\\")\"";
56         // Default to "python" if no binary is given.
57         if (binary.empty())
58                 return "python -tt";
59
60         if (verbose)
61                 lyxerr << "Examining " << binary << "\n";
62         // Check whether this is a python 2 or 3 binary.
63         cmd_ret const out = runCommand(binary + version_info);
64
65         smatch sm;
66         try {
67                 static regex const python_reg("\\((\\d*), (\\d*)\\)");
68                 if (!out.valid || !regex_match(out.result, sm, python_reg))
69                         return string();
70         } catch(regex_error const & /*e*/) {
71                 LYXERR0("Regex error! This should not happen.");
72                 return string();
73         }
74
75         int major = convert<int>(sm.str(1));
76         int minor = convert<int>(sm.str(2));
77         if((major == 2 && minor < 7) || (major == 3 && minor < 5))
78                 return string();
79
80         if (verbose)
81                 lyxerr << "Found Python " << out.result << "\n";
82         // Add the -tt switch so that mixed tab/whitespace
83         // indentation is an error
84         return binary + " -tt";
85 }
86
87
88 static string const find_python_binary()
89 {
90         // This function takes inspiration from PEP 394 and PEP 397
91         // PEP 394 -- The "python" Command on Unix-Like Systems
92         // https://www.python.org/dev/peps/pep-0394/
93         // PEP 397 -- Python launcher for Windows
94         // https://www.python.org/dev/peps/pep-0397/
95
96 #ifdef _WIN32
97         // Check through python launcher whether python 3 is
98         // installed on computer.
99         string command = python23_call("py -3");
100 #else
101         // Check whether python3 in PATH is the right one.
102         string command = python23_call("python3");
103 #endif // _WIN32
104         if (!command.empty())
105                 return command;
106
107 #ifndef _WIN32
108         // python3 does not exists, let us try to find python3.x in PATH
109         // the search is probably broader than required
110         // but we are trying hard to find a valid python binary
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("python3*"));
119                 for (auto bin2 : list) {
120                         string const binary = "\"" + addName(localdir,
121                                 bin2.toLocal8Bit().constData()) + "\"";
122                         command = python23_call(binary, true);
123                         if (!command.empty())
124                                 return command;
125                 }
126         }
127 #endif // !_WIN32
128
129         // python 3 was not found let us look for python 2
130 #ifdef _WIN32
131         command = python23_call("py -2");
132 #else
133         command = python23_call("python2");
134 #endif // _WIN32
135         if (!command.empty())
136                 return command;
137
138 #ifdef _WIN32
139         // python launcher is not installed, let cmd auto check 
140         // PATH for a python.exe
141         command = python23_call("python");
142         if (!command.empty())
143                 return command;
144
145         //failed, prepare to search PATH manually
146         vector<string> const path = getEnvPath("PATH");
147         lyxerr << "Manually looking for python in PATH ...\n";
148         QString const exeName = "python*";
149 #else
150         // python2 does not exists, let us try to find python2.x in PATH
151         // the search is probably broader than required
152         // but we are trying hard to find a valid python binary
153         lyxerr << "Looking for python 2.x ...\n";
154         QString const exeName = "python2*";
155 #endif // _WIN32
156
157         for (auto bin : path) {
158                 QString const dir = toqstr(bin);
159                 string const localdir = dir.toLocal8Bit().constData();
160                 QDir qdir(dir);
161                 qdir.setFilter(QDir::Files | QDir::Executable);
162                 QStringList list = qdir.entryList(QStringList(exeName));
163                 for (auto bin2 : list) {
164                         string const binary = "\"" + addName(localdir,
165                                 bin2.toLocal8Bit().constData()) + "\"";
166                         command = python23_call(binary, true);
167                         if (!command.empty())
168                                 return command;
169                 }
170         }
171
172         // If this happens all hope is lost that this is a sane system
173         lyxerr << "Warning: No python v2.x or 3.x binary found.\n";
174         return python23_call("");
175 }
176
177
178 string const python(bool reset)
179 {
180         static string command = find_python_binary();
181         // FIXME THREAD
182         if (reset) {
183                 command = find_python_binary();
184         }
185         return command;
186 }
187
188 } // namespace os
189 } // namespace support
190 } // namespace lyx