- Fix shebang of pgadmin4-desktop to use python3.11 - New pgadmin4-cloud subpackage that includes now the cloud dependencies and make the pgadmin4-cloud package optional so it's now optional to depend on the azure/aws/google python packages. - Add patch to let pgadmin4 work without cloud support: * make-cloud-packages-optional.patch - Add a optipng script that actually uses pngcrush to compress png images so we don't depend on optipng which is not available in SLE. - Fix pgadmin4-desktop to use a timer instead of threads. It seems there's an issue the way python threads were used with Qt5 that made the script fail to update the systray menu when pgadmin was started. - Add missing python-typer dependency - Add pgadmin4-user.conf file to create the pgadmin user/group using systemd with the new system-user-pgadmin package. - Replace yarn (which is not available in SLE) with local-npm-registry. - Add node_modules service and node_modules.obscpio / node_modules.spec.inc source files which replace vendor.tar.xz that is now removed. - package_deps.patch - dependency fixes - package_git_local.patch - dependency fixes that are needed *after* generating package-lock.json since only registry-supplied packages are available locally. - Update update-vendor.sh script. OBS-URL: https://build.opensuse.org/request/show/1145351 OBS-URL: https://build.opensuse.org/package/show/server:database:postgresql/pgadmin4?expand=0&rev=65
136 lines
4.6 KiB
Python
136 lines
4.6 KiB
Python
#!/usr/bin/python3
|
|
#
|
|
# This is a small script that tries to replace pgadmin4-runtime as
|
|
# a desktop version of pgadmin4.
|
|
|
|
# pgadmin4-runtime uses NW.js (which is based on Chromium and Node.js) which
|
|
# makes it hard to package in a standard way.
|
|
# pgadmin4-desktop tries to be a simple replacement which just runs pgadmin4
|
|
# in runtime mode but uses Qt6 for the GUI in order to show an icon in the
|
|
# system tray and provide two options: open a new browser window with pgAdmin
|
|
# and quit the application.
|
|
#
|
|
# This script is released under the PostgreSQL License.
|
|
# (C) 2023 Antonio Larrosa <alarrosa@suse.com>
|
|
|
|
import subprocess
|
|
import os
|
|
import os.path
|
|
import uuid
|
|
import socket
|
|
import time
|
|
import sys
|
|
import fcntl
|
|
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMenu, QSplashScreen, QAction
|
|
from PyQt5.QtGui import QIcon, QPixmap, QImage, QPalette, QPainter
|
|
from PyQt5.QtCore import QTimer, Qt
|
|
|
|
|
|
class PGAdminDesktop(QApplication):
|
|
def __init__(self):
|
|
super().__init__(sys.argv)
|
|
self.environ = os.environ
|
|
self.pgadmin_process = None
|
|
self.url = None
|
|
|
|
self.setQuitOnLastWindowClosed(False)
|
|
self.aboutToQuit.connect(self.cleanup)
|
|
self.create_ui()
|
|
|
|
pixmap = self.load_splash_pixmap()
|
|
if pixmap:
|
|
self.splash = QSplashScreen(pixmap)
|
|
self.splash.showMessage("Starting pgAdmin.", Qt.AlignmentFlag.AlignBottom)
|
|
self.splash.show()
|
|
else:
|
|
self.splash = None
|
|
|
|
self.run_pgadmin_server()
|
|
QTimer.singleShot(500, self.open_pgadmin)
|
|
|
|
def load_splash_pixmap(self):
|
|
paths = [path + '/pgadmin4/assets/welcome_logo.svg' for path in sys.path]
|
|
paths = [path for path in paths if os.path.exists(path)]
|
|
if not paths:
|
|
return None
|
|
return QPixmap(paths[0])
|
|
|
|
def run_pgadmin_server(self):
|
|
if 'PGADMIN_INT_KEY' not in self.environ:
|
|
self.environ['PGADMIN_INT_KEY'] = str(uuid.uuid4())
|
|
|
|
if 'PGADMIN_INT_PORT' not in self.environ:
|
|
self.environ['PGADMIN_INT_PORT'] = '5051'
|
|
|
|
self.environ['PGADMIN_SERVER_MODE'] = 'OFF'
|
|
self.pgadmin_process = subprocess.Popen(['pgadmin4'],
|
|
env=self.environ, shell=True)
|
|
|
|
def create_ui(self):
|
|
icon = QIcon.fromTheme("pgadmin4")
|
|
self.tray = QSystemTrayIcon()
|
|
self.tray.setIcon(icon)
|
|
self.tray.setVisible(True)
|
|
|
|
menu = QMenu()
|
|
|
|
self.title = QAction("pgAdmin")
|
|
self.title.setEnabled(False)
|
|
menu.addAction(self.title)
|
|
menu.addSeparator()
|
|
|
|
self.openPGAdminAction = QAction("New Window")
|
|
menu.addAction(self.openPGAdminAction)
|
|
self.openPGAdminAction.triggered.connect(self.open_pgadmin)
|
|
|
|
self.quitAction = QAction("Quit")
|
|
menu.addAction(self.quitAction)
|
|
self.quitAction.triggered.connect(self.quit)
|
|
|
|
self.tray.setContextMenu(menu)
|
|
|
|
def check_if_pgadmin_is_running(self):
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.settimeout(1)
|
|
result = sock.connect_ex(('127.0.0.1',
|
|
int(self.environ['PGADMIN_INT_PORT'])))
|
|
|
|
if result == 0:
|
|
if self.splash:
|
|
self.splash.hide()
|
|
port = self.environ['PGADMIN_INT_PORT']
|
|
key = self.environ['PGADMIN_INT_KEY']
|
|
subprocess.run(["xdg-open", f"http://127.0.0.1:{port}/?key={key}"])
|
|
|
|
self.openPGAdminAction.setText("New Window")
|
|
self.openPGAdminAction.setEnabled(True)
|
|
else:
|
|
self.checks_for_pgadmin += 1
|
|
if self.checks_for_pgadmin < 15:
|
|
dots = "." * (self.checks_for_pgadmin % 3 + 1)
|
|
self.openPGAdminAction.setText("Opening pgAdmin" + dots)
|
|
if self.splash and not self.splash.isHidden():
|
|
self.splash.showMessage("Starting pgAdmin" + dots, Qt.AlignmentFlag.AlignBottom)
|
|
|
|
QTimer.singleShot(1000, self.check_if_pgadmin_is_running)
|
|
else:
|
|
error_msg = 'Timeout waiting for pgAdmin to start. Exiting...'
|
|
print(error_msg)
|
|
self.splash.showMessage(error_msg, Qt.AlignmentFlag.AlignBottom)
|
|
QTimer.singleShot(10000, self.quit)
|
|
|
|
|
|
def open_pgadmin(self):
|
|
self.openPGAdminAction.setText("Opening pgAdmin...")
|
|
self.openPGAdminAction.setEnabled(False)
|
|
self.checks_for_pgadmin = 0
|
|
QTimer.singleShot(1000, self.check_if_pgadmin_is_running)
|
|
|
|
def cleanup(self):
|
|
self.pgadmin_process.kill()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app = PGAdminDesktop()
|
|
sys.exit(app.exec())
|