mirror of
https://github.com/archlinux/aur.git
synced 2026-03-05 06:42:23 +01:00
474 lines
17 KiB
Diff
474 lines
17 KiB
Diff
From 3605c5c714d9915beafc1d8a7e1360e20eb4980b Mon Sep 17 00:00:00 2001
|
|
From: Dave Page <dpage@pgadmin.org>
|
|
Date: Fri, 6 Jan 2017 12:11:35 +0100
|
|
Subject: [PATCH] Simplify Server's python setup
|
|
|
|
---
|
|
runtime/BrowserWindow.cpp | 6 +-
|
|
runtime/ConfigWindow.cpp | 16 +++-
|
|
runtime/ConfigWindow.h | 6 +-
|
|
runtime/ConfigWindow.ui | 22 ++++-
|
|
runtime/Server.cpp | 227 +++++++++++-----------------------------------
|
|
runtime/Server.h | 6 +-
|
|
runtime/pgAdmin4.cpp | 6 +-
|
|
7 files changed, 97 insertions(+), 192 deletions(-)
|
|
|
|
diff --git a/runtime/BrowserWindow.cpp b/runtime/BrowserWindow.cpp
|
|
index 4b96abe50c89b14c..6279cd4b303d8e06 100644
|
|
--- a/runtime/BrowserWindow.cpp
|
|
+++ b/runtime/BrowserWindow.cpp
|
|
@@ -1215,17 +1215,17 @@ void BrowserWindow::preferences()
|
|
|
|
ConfigWindow *dlg = new ConfigWindow();
|
|
dlg->setWindowTitle(QWidget::tr("Configuration"));
|
|
- dlg->setPythonPath(settings.value("PythonPath").toString());
|
|
+ dlg->setPythonExecutable(settings.value("PythonExecutable").toString());
|
|
dlg->setApplicationPath(settings.value("ApplicationPath").toString());
|
|
dlg->setModal(true);
|
|
ok = dlg->exec();
|
|
|
|
- QString pythonpath = dlg->getPythonPath();
|
|
+ QString pythonexecutable = dlg->getPythonExecutable();
|
|
QString applicationpath = dlg->getApplicationPath();
|
|
|
|
if (ok)
|
|
{
|
|
- settings.setValue("PythonPath", pythonpath);
|
|
+ settings.setValue("PythonExecutable", pythonexecutable);
|
|
settings.setValue("ApplicationPath", applicationpath);
|
|
}
|
|
}
|
|
diff --git a/runtime/ConfigWindow.cpp b/runtime/ConfigWindow.cpp
|
|
index 3fb1a2738eb89ec0..c31345bf08d06d88 100644
|
|
--- a/runtime/ConfigWindow.cpp
|
|
+++ b/runtime/ConfigWindow.cpp
|
|
@@ -17,6 +17,14 @@ ConfigWindow::ConfigWindow(QWidget *parent) :
|
|
ui(new Ui::ConfigWindow)
|
|
{
|
|
ui->setupUi(this);
|
|
+
|
|
+#ifdef PYTHON2
|
|
+ ui->pythonExecutableLineEdit->setPlaceholderText(
|
|
+ QString(QWidget::tr("The Python 2 executable to use (may be within a virtual environment)")));
|
|
+#else
|
|
+ ui->pythonExecutableLineEdit->setPlaceholderText(
|
|
+ QString(QWidget::tr("The Python 3 executable to use (may be within a virtual environment)")));
|
|
+#endif
|
|
}
|
|
|
|
ConfigWindow::~ConfigWindow()
|
|
@@ -34,9 +42,9 @@ void ConfigWindow::on_buttonBox_rejected()
|
|
this->close();
|
|
}
|
|
|
|
-QString ConfigWindow::getPythonPath()
|
|
+QString ConfigWindow::getPythonExecutable()
|
|
{
|
|
- return ui->pythonPathLineEdit->text();
|
|
+ return ui->pythonExecutableLineEdit->text();
|
|
}
|
|
|
|
QString ConfigWindow::getApplicationPath()
|
|
@@ -45,9 +53,9 @@ QString ConfigWindow::getApplicationPath()
|
|
}
|
|
|
|
|
|
-void ConfigWindow::setPythonPath(QString path)
|
|
+void ConfigWindow::setPythonExecutable(QString path)
|
|
{
|
|
- ui->pythonPathLineEdit->setText(path);
|
|
+ ui->pythonExecutableLineEdit->setText(path);
|
|
}
|
|
|
|
void ConfigWindow::setApplicationPath(QString path)
|
|
diff --git a/runtime/ConfigWindow.h b/runtime/ConfigWindow.h
|
|
index 0027a742aca7b762..c4487fcc6e97f354 100644
|
|
--- a/runtime/ConfigWindow.h
|
|
+++ b/runtime/ConfigWindow.h
|
|
@@ -26,10 +26,10 @@ public:
|
|
explicit ConfigWindow(QWidget *parent = 0);
|
|
~ConfigWindow();
|
|
|
|
- QString getPythonPath();
|
|
+ QString getPythonExecutable();
|
|
QString getApplicationPath();
|
|
|
|
- void setPythonPath(QString path);
|
|
+ void setPythonExecutable(QString path);
|
|
void setApplicationPath(QString path);
|
|
|
|
private slots:
|
|
@@ -38,7 +38,7 @@ private slots:
|
|
|
|
private:
|
|
Ui::ConfigWindow *ui;
|
|
- QString m_pythonpath, m_applicationpath;
|
|
+ QString m_pythonexecutable, m_applicationpath;
|
|
};
|
|
|
|
#endif // CONFIGWINDOW_H
|
|
diff --git a/runtime/ConfigWindow.ui b/runtime/ConfigWindow.ui
|
|
index 40d87be43803204a..8b379052a1da8cd0 100644
|
|
--- a/runtime/ConfigWindow.ui
|
|
+++ b/runtime/ConfigWindow.ui
|
|
@@ -29,14 +29,24 @@
|
|
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
|
</property>
|
|
<item row="0" column="0">
|
|
- <widget class="QLabel" name="pythonPathLabel">
|
|
+ <widget class="QLabel" name="pythonExecutableLabel">
|
|
+ <property name="sizeIncrement">
|
|
+ <size>
|
|
+ <width>0</width>
|
|
+ <height>1</height>
|
|
+ </size>
|
|
+ </property>
|
|
<property name="text">
|
|
- <string>Python Path</string>
|
|
+ <string>Python Executable</string>
|
|
</property>
|
|
</widget>
|
|
</item>
|
|
<item row="0" column="1">
|
|
- <widget class="QLineEdit" name="pythonPathLineEdit"/>
|
|
+ <widget class="QLineEdit" name="pythonExecutableLineEdit">
|
|
+ <property name="placeholderText">
|
|
+ <string>The python executable to use (may be within a virtual environment)</string>
|
|
+ </property>
|
|
+ </widget>
|
|
</item>
|
|
<item row="1" column="0">
|
|
<widget class="QLabel" name="applicationPathLabel">
|
|
@@ -46,7 +56,11 @@
|
|
</widget>
|
|
</item>
|
|
<item row="1" column="1">
|
|
- <widget class="QLineEdit" name="applicationPathLineEdit"/>
|
|
+ <widget class="QLineEdit" name="applicationPathLineEdit">
|
|
+ <property name="placeholderText">
|
|
+ <string>The directory containing pgAdmin4.py (do not include the file name)</string>
|
|
+ </property>
|
|
+ </widget>
|
|
</item>
|
|
</layout>
|
|
</item>
|
|
diff --git a/runtime/Server.cpp b/runtime/Server.cpp
|
|
index e5be20569faaf6c4..408ae62b6c4aea1c 100644
|
|
--- a/runtime/Server.cpp
|
|
+++ b/runtime/Server.cpp
|
|
@@ -22,183 +22,84 @@
|
|
// App headers
|
|
#include "Server.h"
|
|
|
|
-static void add_to_path(QString &python_path, QString path, bool prepend=false)
|
|
-{
|
|
- if (!python_path.contains(path))
|
|
- {
|
|
- if (!prepend)
|
|
- {
|
|
- if (!python_path.isEmpty() && !python_path.endsWith(";"))
|
|
- python_path.append(";");
|
|
-
|
|
- python_path.append(path);
|
|
- }
|
|
- else
|
|
- {
|
|
- if (!python_path.isEmpty() && !python_path.startsWith(";"))
|
|
- python_path.prepend(";");
|
|
-
|
|
- python_path.prepend(path);
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
Server::Server(quint16 port)
|
|
{
|
|
// Appserver port
|
|
m_port = port;
|
|
- m_wcAppName = NULL;
|
|
|
|
// Initialise Python
|
|
- Py_NoSiteFlag=1;
|
|
- Py_DontWriteBytecodeFlag=1;
|
|
+ Py_DontWriteBytecodeFlag = 1;
|
|
+
|
|
+ // Get the application directory
|
|
+ QString appDir = qApp->applicationDirPath();
|
|
+
|
|
+ // Build (and canonicalise) the virtual environment path
|
|
+#ifdef Q_OS_MAC
|
|
+ QFileInfo venvBinPath(appDir + "/../Resources/venv/bin");
|
|
+#elif defined(Q_OS_WIN)
|
|
+ QFileInfo venvBinPath(appDir + "/../venv");
|
|
+#else
|
|
+ QFileInfo venvBinPath(appDir + "/../venv/bin");
|
|
+#endif
|
|
+ QString binPath = venvBinPath.canonicalFilePath();
|
|
+
|
|
+ if (binPath.isEmpty())
|
|
+ {
|
|
+ // Use default Python environment from the config, or lastly, PATH
|
|
+ QSettings settings;
|
|
+ binPath.append(settings.value("PythonExecutable").toString());
|
|
+ if (binPath.isEmpty())
|
|
+ binPath.append("python");
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ binPath.append("/python");
|
|
+ }
|
|
|
|
// Python3 requires conversion of char * to wchar_t *, so...
|
|
#ifdef PYTHON2
|
|
- Py_SetProgramName(PGA_APP_NAME.toUtf8().data());
|
|
+ QByteArray appName = binPath.toLocal8Bit();
|
|
+ m_pyAppName = new char[strlen(appName.data()) + 1];
|
|
+ strcpy(m_pyAppName, appName.data());
|
|
+ qDebug() << "Python interpreter: " << QString::fromLocal8Bit(m_pyAppName);
|
|
#else
|
|
- char *appName = PGA_APP_NAME.toUtf8().data();
|
|
- const size_t cSize = strlen(appName)+1;
|
|
- m_wcAppName = new wchar_t[cSize];
|
|
- mbstowcs (m_wcAppName, appName, cSize);
|
|
- Py_SetProgramName(m_wcAppName);
|
|
+ std::wstring appName = binPath.toStdWString();
|
|
+ m_pyAppName = new wchar_t[wcslen(appName.c_str()) + 1];
|
|
+ wcscpy(m_pyAppName, appName.c_str());
|
|
+ qDebug() << "Python interpreter: " << QString::fromWCharArray(m_pyAppName);
|
|
#endif
|
|
-
|
|
- // Setup the search path
|
|
- QSettings settings;
|
|
- QString python_path = settings.value("PythonPath").toString();
|
|
-
|
|
- // Get the application directory
|
|
- QString app_dir = qApp->applicationDirPath(),
|
|
- path_env = qgetenv("PATH"),
|
|
- pythonHome;
|
|
- QStringList path_list;
|
|
- int i;
|
|
-
|
|
-#ifdef Q_OS_MAC
|
|
- // In the case we're running in a release appbundle, we need to ensure the
|
|
- // bundled virtual env is included in the Python path. We include it at the
|
|
- // end, so expert users can override the path, but we do not save it, because
|
|
- // if users move the app bundle, we'll end up with dead entries
|
|
-
|
|
- // Build (and canonicalise) the virtual environment path
|
|
- QFileInfo venvBinPath(app_dir + "/../Resources/venv/bin");
|
|
- QFileInfo venvLibPath(app_dir + "/../Resources/venv/lib/python");
|
|
- QFileInfo venvDynLibPath(app_dir + "/../Resources/venv/lib/python/lib-dynload");
|
|
- QFileInfo venvSitePackagesPath(app_dir + "/../Resources/venv/lib/python/site-packages");
|
|
- QFileInfo venvPath(app_dir + "/../Resources/venv");
|
|
-
|
|
- // Prepend the bin directory to the path
|
|
- add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
|
|
- // Append the path, if it's not already there
|
|
- add_to_path(python_path, venvLibPath.canonicalFilePath());
|
|
- add_to_path(python_path, venvDynLibPath.canonicalFilePath());
|
|
- add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
|
|
- add_to_path(pythonHome, venvPath.canonicalFilePath());
|
|
-#elif defined(Q_OS_WIN)
|
|
-
|
|
- // In the case we're running in a release application, we need to ensure the
|
|
- // bundled virtual env is included in the Python path. We include it at the
|
|
- // end, so expert users can override the path, but we do not save it.
|
|
-
|
|
- // Build (and canonicalise) the virtual environment path
|
|
- QFileInfo venvBinPath(app_dir + "/../venv");
|
|
- QFileInfo venvLibPath(app_dir + "/../venv/Lib");
|
|
- QFileInfo venvDLLsPath(app_dir + "/../venv/DLLs");
|
|
- QFileInfo venvSitePackagesPath(app_dir + "/../venv/Lib/site-packages");
|
|
- QFileInfo venvPath(app_dir + "/../venv");
|
|
-
|
|
- // Prepend the bin directory to the path
|
|
- add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
|
|
- // Append paths, if they're not already there
|
|
- add_to_path(python_path, venvLibPath.canonicalFilePath());
|
|
- add_to_path(python_path, venvDLLsPath.canonicalFilePath());
|
|
- add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
|
|
- add_to_path(pythonHome, venvPath.canonicalFilePath());
|
|
-#else
|
|
- // Build (and canonicalise) the virtual environment path
|
|
- QFileInfo venvBinPath(app_dir + "/../venv/bin");
|
|
- QFileInfo venvLibPath(app_dir + "/../venv/lib/python");
|
|
- QFileInfo venvDynLibPath(app_dir + "/../venv/lib/python/lib-dynload");
|
|
- QFileInfo venvSitePackagesPath(app_dir + "/../venv/lib/python/site-packages");
|
|
- QFileInfo venvPath(app_dir + "/../venv");
|
|
-
|
|
- // Prepend the bin directory to the path
|
|
- add_to_path(path_env, venvBinPath.canonicalFilePath(), true);
|
|
- // Append the path, if it's not already there
|
|
- add_to_path(python_path, venvLibPath.canonicalFilePath());
|
|
- add_to_path(python_path, venvDynLibPath.canonicalFilePath());
|
|
- add_to_path(python_path, venvSitePackagesPath.canonicalFilePath());
|
|
- add_to_path(pythonHome, venvPath.canonicalFilePath());
|
|
-#endif
|
|
-
|
|
- qputenv("PATH", path_env.toUtf8().data());
|
|
-
|
|
- if (python_path.length() > 0)
|
|
- {
|
|
- // Split the path setting into individual entries
|
|
- path_list = python_path.split(";", QString::SkipEmptyParts);
|
|
- python_path = QString();
|
|
-
|
|
- // Add new additional path elements
|
|
- for (i = path_list.size() - 1; i >= 0 ; --i)
|
|
- {
|
|
- python_path.append(path_list.at(i));
|
|
- if (i > 0)
|
|
- {
|
|
-#if defined(Q_OS_WIN)
|
|
- python_path.append(";");
|
|
-#else
|
|
- python_path.append(":");
|
|
-#endif
|
|
- }
|
|
- }
|
|
- qputenv("PYTHONPATH", python_path.toUtf8().data());
|
|
- }
|
|
-
|
|
- qDebug() << "Python path: " << python_path
|
|
- << "\nPython Home: " << pythonHome;
|
|
- if (!pythonHome.isEmpty())
|
|
- {
|
|
-#ifdef PYTHON2
|
|
- Py_SetPythonHome(pythonHome.toUtf8().data());
|
|
-#else
|
|
- char *python_home = pythonHome.toUtf8().data();
|
|
- const size_t cSize = strlen(python_home) + 1;
|
|
- wchar_t* wcPythonHome = new wchar_t[cSize];
|
|
- mbstowcs (wcPythonHome, python_home, cSize);
|
|
-
|
|
- Py_SetPythonHome(wcPythonHome);
|
|
-#endif
|
|
- }
|
|
+ //Py_SetProgramName(m_pyAppName);
|
|
|
|
Py_Initialize();
|
|
|
|
+ /*
|
|
+ * Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
|
|
+ * versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
|
|
+ * which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
|
|
+ * Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
|
|
+ */
|
|
+ PySys_SetArgvEx(1, &m_pyAppName, 0);
|
|
+
|
|
// Get the current path
|
|
PyObject* sysPath = PySys_GetObject((char*)"path");
|
|
-
|
|
- // Add new additional path elements
|
|
- for (i = path_list.size() - 1; i >= 0 ; --i)
|
|
- {
|
|
+ PyObject* sysPathRepr = PyObject_Repr(sysPath);
|
|
#ifdef PYTHON2
|
|
- PyList_Append(sysPath, PyString_FromString(path_list.at(i).toUtf8().data()));
|
|
+ qDebug() << "Python path: " << QString::fromLocal8Bit(PyString_AsString(sysPathRepr));
|
|
#else
|
|
-#if PY_MINOR_VERSION > 2
|
|
- PyList_Append(sysPath, PyUnicode_DecodeFSDefault(path_list.at(i).toUtf8().data()));
|
|
-#else
|
|
- PyList_Append(sysPath, PyBytes_FromString(path_list.at(i).toUtf8().data()));
|
|
+ PyObject* sysPathBytes = PyUnicode_AsEncodedString(sysPathRepr, "utf8", "replace");
|
|
+ qDebug() << "Python path: " << QString::fromUtf8(PyBytes_AsString(sysPathBytes));
|
|
+ Py_DECREF(sysPathBytes);
|
|
#endif
|
|
-#endif
|
|
- }
|
|
+ Py_DECREF(sysPathRepr);
|
|
}
|
|
|
|
Server::~Server()
|
|
{
|
|
- if (m_wcAppName)
|
|
- delete m_wcAppName;
|
|
-
|
|
// Shutdown Python
|
|
Py_Finalize();
|
|
+
|
|
+ if (m_pyAppName)
|
|
+ delete [] m_pyAppName;
|
|
}
|
|
|
|
bool Server::Init()
|
|
@@ -258,33 +159,11 @@ void Server::run()
|
|
|
|
// Run the app!
|
|
#ifdef PYTHON2
|
|
- /*
|
|
- * Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
|
|
- * versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
|
|
- * which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
|
|
- * Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
|
|
- */
|
|
- char* n_argv[] = { m_appfile.toUtf8().data() };
|
|
- PySys_SetArgv(1, n_argv);
|
|
-
|
|
PyObject* PyFileObject = PyFile_FromString(m_appfile.toUtf8().data(), (char *)"r");
|
|
int ret = PyRun_SimpleFile(PyFile_AsFile(PyFileObject), m_appfile.toUtf8().data());
|
|
if (ret != 0)
|
|
setError(tr("Failed to launch the application server, server thread exiting."));
|
|
#else
|
|
- /*
|
|
- * Untrusted search path vulnerability in the PySys_SetArgv API function in Python 2.6 and earlier, and possibly later
|
|
- * versions, prepends an empty string to sys.path when the argv[0] argument does not contain a path separator,
|
|
- * which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
|
|
- * Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
|
|
- */
|
|
- char *appName = m_appfile.toUtf8().data();
|
|
- const size_t cSize = strlen(appName)+1;
|
|
- wchar_t* wcAppName = new wchar_t[cSize];
|
|
- mbstowcs (wcAppName, appName, cSize);
|
|
- wchar_t* n_argv[] = { wcAppName };
|
|
- PySys_SetArgv(1, n_argv);
|
|
-
|
|
int fd = fileno(cp);
|
|
PyObject* PyFileObject = PyFile_FromFd(fd, m_appfile.toUtf8().data(), (char *)"r", -1, NULL, NULL,NULL,1);
|
|
if (PyRun_SimpleFile(fdopen(PyObject_AsFileDescriptor(PyFileObject),"r"), m_appfile.toUtf8().data()) != 0)
|
|
diff --git a/runtime/Server.h b/runtime/Server.h
|
|
index 8df8503bb553eca4..5cc51f3d8b3e1f9b 100644
|
|
--- a/runtime/Server.h
|
|
+++ b/runtime/Server.h
|
|
@@ -39,7 +39,11 @@ private:
|
|
QString m_error;
|
|
|
|
quint16 m_port;
|
|
- wchar_t *m_wcAppName;
|
|
+#ifdef PYTHON2
|
|
+ char *m_pyAppName;
|
|
+#else
|
|
+ wchar_t *m_pyAppName;
|
|
+#endif
|
|
};
|
|
|
|
#endif // SERVER_H
|
|
diff --git a/runtime/pgAdmin4.cpp b/runtime/pgAdmin4.cpp
|
|
index b1f470d811a7cfb1..d9a47178f0dbad16 100644
|
|
--- a/runtime/pgAdmin4.cpp
|
|
+++ b/runtime/pgAdmin4.cpp
|
|
@@ -111,17 +111,17 @@ int main(int argc, char * argv[])
|
|
|
|
ConfigWindow *dlg = new ConfigWindow();
|
|
dlg->setWindowTitle(QWidget::tr("Configuration"));
|
|
- dlg->setPythonPath(settings.value("PythonPath").toString());
|
|
+ dlg->setPythonExecutable(settings.value("PythonExecutable").toString());
|
|
dlg->setApplicationPath(settings.value("ApplicationPath").toString());
|
|
dlg->setModal(true);
|
|
ok = dlg->exec();
|
|
|
|
- QString pythonpath = dlg->getPythonPath();
|
|
+ QString pythonexecutable = dlg->getPythonExecutable();
|
|
QString applicationpath = dlg->getApplicationPath();
|
|
|
|
if (ok)
|
|
{
|
|
- settings.setValue("PythonPath", pythonpath);
|
|
+ settings.setValue("PythonExecutable", pythonexecutable);
|
|
settings.setValue("ApplicationPath", applicationpath);
|
|
settings.sync();
|
|
}
|
|
--
|
|
2.11.0
|
|
|