Compare commits

..
75 Commits
Author SHA1 Message Date
Akshay Joshi 1347c89d61 Update version for release. 2020-05-25 17:11:12 +05:30
Akshay Joshi b1cbcc7ef6 Fixed data truncation issue when updating the data of type character with length. Fixes #5481 2020-05-25 17:05:47 +05:30
Domenico Sgarbossa 22c3a2649b Update Italian translation. 2020-05-25 11:24:37 +05:30
Identifier Anonymous 2bb0b25688 Update Japanese translation. 2020-05-25 11:13:37 +05:30
Libor M 2aefc6361e Update Czech translation. 2020-05-25 11:09:52 +05:30
Dave Page 83cb01b8cd Update dependencies in the Docker container and remove PG 9.4 utilities from the Docker container as it's now out of support.
Fixes #5552.
Fixes #5553.
2020-05-22 17:02:12 +01:00
Akshay Joshi d42b712ee4 Update message catalogs 2020-05-22 19:13:13 +05:30
Dave Page fec458dd6a Add repo build information to the Debian README. 2020-05-22 11:58:24 +01:00
Akshay Joshi 9b8902dfb8 Fixed the SQL help issue for EDB Postgres Advanced Server. Fixes #4099 2020-05-22 14:11:58 +05:30
Dave Page 4a8037fc6a Test commit 2020-05-22 09:12:54 +01:00
Yogesh Mahajan d927a517aa Fixed feature test failures on the selenium grid for concurrent execution. 2020-05-21 19:44:28 +05:30
Dave Page 96939ba985 Add information to the Redhat README about signing RPMs, creating a repository and creating repo RPMs. 2020-05-21 12:47:41 +01:00
Dave Page 414b074bad Tidy up the web setup script output. 2020-05-19 14:27:23 +01:00
Yogesh Jain 7b1cac6914 Fixed an issue where clicking on Select All button, not selecting all the options in pgAgent job scheduler. Fixes #5496 2020-05-19 13:54:21 +05:30
Dave Page 4aaacfd5b0 Add the public key for our packages for the RPM build. 2020-05-18 15:43:17 +01:00
Dave Page 52187306ce Create the dist/ directory if needed. 2020-05-18 15:37:18 +01:00
Dave Page 0e799b16b0 Only try to run make clean if there is a Makefile present. 2020-05-18 11:18:03 +01:00
Dave Page 569d05df4e Remove obsolete file. 2020-05-18 11:17:07 +01:00
Dave Page eac5fe5157 Cleanup and refactor the macOS build scripts. Fixes #5525 2020-05-18 10:22:59 +01:00
Dave Page 5337514c63 Allow the base directory for the repo to be overridden from the environment. 2020-05-18 10:22:28 +01:00
Khushboo Vashi d1bdb178e2 Fixed an issue where if LDAP_SEARCH_BASE_DN is not set then, the value for LDAP_BASE_DN will be considered. Fixes #5487 2020-05-18 12:35:34 +05:30
Yogesh Mahajan 9f445dc052 Improve code coverage and API test cases for Indexes. Fixes #5333 2020-05-18 12:29:33 +05:30
Aditya Toshniwal d58c33dec0 Search object UI improvements. Fixes #5493 2020-05-18 11:29:12 +05:30
Khushboo Vashi 0f56c25893 Changed the user identity from email to username in the log file.
refs #5452
2020-05-18 11:01:20 +05:30
Dave Page 762784d2b5 Add a script for generating a repo RPM. 2020-05-15 11:22:28 +01:00
Pradip Parkale 6d6cd19b37 Improve code coverage and API test cases for Triggers and Compound Triggers. Fixes #5335 2020-05-15 12:50:50 +05:30
Akshay Joshi c0451cd454 Added connected pgAdmin user and connection name in the log file. Fixes #5452
Patch By: Nico T
2020-05-13 17:43:21 +05:30
Akshay Joshi 0620fafb6c Fixed PEP8 issues discovered after pycodestyle gets upgraded. 2020-05-13 17:14:32 +05:30
Khushboo Vashi a9a1a975a6 Added compatibility for Flask-Security-Too version 3.2 2020-05-13 16:02:38 +05:30
Akshay Joshi 8a06a836f4 Ensure that pgAdmin4 should be compiled with older OSX SDK's. 2020-05-12 17:22:22 +05:30
Yogesh Jain dba5761ad0 Fixed an issue where clicking on the cross button of the alert box on the login page is not working. Fixes #4033 2020-05-12 17:22:22 +05:30
Yogesh Mahajan 8ec1d4c9eb Fixed feature tests failure on chrome caused due to selenium grid implementation changes. 2020-05-12 17:22:22 +05:30
Akshay Joshi 46e9924ebb Fixed Unicode decode error 'utf-8' codec can't decode byte. Fixes #5510
It's a regression of commit id: 04d6d4e2ccc129baa698471ce0680ccabe2282be
2020-05-12 17:22:22 +05:30
Dave Page 12a7ce54d9 Ubuntu 20.04 needs python3-wheel to be explicitly installed. 2020-05-11 15:08:40 +01:00
Akshay Joshi 9d08776824 Ensure that maintenance job should be worked properly for indexes under a materialized view. Fixes #4223. 2020-05-11 16:47:36 +05:30
Akshay Joshi 073d90c4a6 Fixed internal server error when clicking on Triggers -> 'Enable All' for partitions. Fixes #5052 2020-05-11 15:18:39 +05:30
Dave Page 7d4ddc3910 Clarify and correct the docs on enabling the pl/debugger plugin on the server per Jakob Egger. Fixes #5503 2020-05-11 09:05:15 +01:00
Yogesh Mahajan 1294c089a8 Implement Selenium Grid to run multiple tests across different browsers, operating systems, and machines in parallel. Fixes #5255 2020-05-11 12:11:31 +05:30
Aditya Toshniwal b64896f558 Fixed generated SQL issue for auto vacuum options. Fixes #5398
Fixed some more issues:

 1) pgAdmin allows only true or false values for autovacuum_enabled,
    and there is no way to reset it individually without disabling a custom auto vacuum.
    To fix this, the control is changed from the switch to three state buttons.
 2) Setting any vacuum options to zero made the option disappear from the SQL.
 3) Right-click on a table with vacuum options set and create a new table.
 4) The parameters tab will have the options prefilled.
 5) Changed the UI a bit to remove unnecessary space around. Added "Autovacuum" before enabled.
    The SQL generated was appending a ".0" to decimal vacuum options. Changed to remove the leading ".0".
2020-05-08 14:30:30 +05:30
Ashesh Vashi e73e2d2502 Fixed the errors, and warnings reported by pylama.
TODO::
- Don't use unicode in Python 3 for removing the support of Python 2 (
  psycopg2 driver - __init__.py, server_manager.py).
- Merge the lastest pgcli (version: 3.0.0) for SQL autocompletion.
2020-05-08 14:13:38 +05:30
Satish V 9338bdcb3a Fixed an issue where the newly added table is not alphabetically added to the tree. Fixes #5434
Fixed an issue when renaming the column not added in the proper order. Fixes #5450
2020-05-08 12:52:03 +05:30
Khushboo Vashi d68e6bd892 Remove Python2 modules.
refs #5443
2020-05-08 12:28:21 +05:30
Pradip Parkale 057a2b2312 Improve code coverage and API test cases for the Rules module. Fixes #5334 2020-05-07 16:27:58 +05:30
Dave Page 46d186a49f Show the startup log as well as the server log in the runtime's log viewer. Fixes #5489 2020-05-07 11:01:02 +01:00
Dave Page 7164c677de UI layout tweaks. 2020-05-07 10:39:28 +01:00
Akshay Joshi 6ad46e1860 Fixed invalid literal issue when removing the connection limit for the existing role. Fixes #5001 2020-05-07 13:14:45 +05:30
Akshay Joshi a662d866af Ensure that 'With OID' option should be disabled while taking backup of database server version 12 and above. Fixes #4840 2020-05-07 11:56:43 +05:30
Akshay Joshi a0940fd145 Typecast the object to 'text' before using it in length() function, so that correct length function gets called. 2020-05-06 17:34:18 +05:30
Nagesh Dhope f61448eea2 Fixed an issue where the background job creation fails if there is only a version-specific python binary available in PATH. Fixes #5480 2020-05-06 12:38:06 +05:30
Akshay Joshi 943495de31 Fixed list sorting issue in the schema diff tool. Fixes #5440
Fixed an issue while comparing the two identical schemas using the schema diff tool. Fixes #5449
2020-05-06 11:25:43 +05:30
Aditya Toshniwal 059f1e38cc Refactor pgAdmin4.py so it can be imported and is a lot more readable. Fixes #5455 2020-05-04 15:28:44 +01:00
Aditya Toshniwal 370094274c Fixed post-login redirect location when running in server mode under a non-default root. Fixes #5473 2020-05-04 15:00:45 +01:00
Dave Page 04d6d4e2cc Remove support for Python 2. Fixes #5443 2020-05-04 14:58:49 +01:00
Dave Page cf31d0187b Remove support for building the macOS appbundle with Python 2.7. Refs #5443 2020-05-04 14:56:28 +01:00
Akshay Joshi f1963401d6 Raise an exception under Python < 3.4 for WSGI mode.
refs #5443
2020-05-04 15:06:45 +05:30
Dave Page 94bd1f1680 Cleanup Python detection in the runtime project file. Fixes #5444 2020-05-04 10:20:51 +01:00
Dave Page 908e156113 Correct ipv4 "all interfaces" address in the container docs, per Frank Limpert. Fixes #5466 2020-05-04 09:25:05 +01:00
Ganesh Jaybhay 5fe7813f9f Fixed an issue where select2 hover is inconsistent for the SSL field in create server dialog. Fixes #5469 2020-05-04 13:19:13 +05:30
Satish V d61b8eb1b3 Gracefully informed the user that the database is already connected when they click on 'Connect Database...'. Fixes #3694 2020-05-04 13:08:56 +05:30
Murtuza Zabuawala 0fc2afb829 Add Reverse Engineered and Modified SQL tests for Column and Type. 2020-05-04 12:48:24 +05:30
Yogesh Jain cc2e3ece7a Ensure that file browse home button should point to /Users/akshayjoshi rather than /. Fixes #4279 2020-05-04 12:40:19 +05:30
Khushboo Vashi 5656f756e6 Ensure that the dependencies tab shows correct information for Synonyms. Fixes #5422 2020-05-04 12:23:18 +05:30
Dave Page 9bdf900b25 Rename README 2020-05-01 15:18:29 +01:00
Dave Page 0ec60a6f85 Minor cleanup and modernisation. 2020-05-01 15:14:46 +01:00
Dave Page 70e24ba059 Rename the README and fix it up to match modern reality. 2020-05-01 15:14:04 +01:00
Akshay Joshi ad80217593 Remove Python2 references from the source code.
refs #5443

Initial patch: Neel Patel
2020-04-30 17:22:48 +05:30
Dave Page 7dd00a1494 Raise an exception under Python < 3.4.
It also cleans up the README to remove references to Python 2
and removes Python 2-isms from the main config.

refs #5443
2020-04-30 14:17:00 +05:30
Dave Page 109051e1d5 Remove Python 2 support from the desktop runtime
refs #5443
2020-04-30 13:04:09 +05:30
Dave Page 86afec860f Remove Python 2 support from the Python tests.
refs #5443
2020-04-30 12:56:45 +05:30
Dave Page 393741fd9d Remove Python 2.7 support from the wheel package.
refs #5443
2020-04-30 12:51:58 +05:30
Dave Page e8a4b46ba1 Another attempt at fixing the 'do we need the --embed flag for Python' problem.
This change looks at the output from python-config --help (which may go
to stderr or stdout), and if it includes --embed, adds it to the later
call to get the libs string.
2020-04-29 16:19:54 +01:00
Dave Page 97be3d8179 Don't rely on python-config sending the help message to stderr, as older versions seem to use stdout. 2020-04-29 15:49:16 +01:00
Dave Page 505956d1fa OK, another attempt at this as it fails on non-Linux non-Python 3.8. 2020-04-29 14:29:47 +01:00
Dave Page f7ef86dced Sigh. Remove extraneous closing bracket. It's always a bracket. 2020-04-29 14:04:32 +01:00
Dave Page 3138f36e05 Fix the runtime build with Python 3.8 on Linux 2020-04-29 13:55:53 +01:00
414 changed files with 21480 additions and 15269 deletions

No files matched your search

+1
View File
@@ -41,6 +41,7 @@ web/config_local.py
web/pgadmin/misc/themes/pgadmin.themes.json
web/geckodriver.log
web/regression/test_config.json
web/regression/.coveragerc
node_modules/
web/pgAdmin/static/js/generated
web/pgadmin/static/js/generated
+5 -11
View File
@@ -12,7 +12,7 @@
# and clean up the web/ source code
#########################################################################
FROM node:10-alpine AS app-builder
FROM node:12-alpine3.11 AS app-builder
RUN apk add --no-cache \
autoconf \
@@ -66,7 +66,7 @@ RUN npm install && \
# Now, create a documentation build container for the Sphinx docs
#########################################################################
FROM python:3.7-alpine3.10 as docs-builder
FROM python:3.8-alpine3.11 as docs-builder
# Install only dependencies absolutely required for documentation building
RUN apk add --no-cache \
@@ -98,21 +98,15 @@ RUN LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 make -C /pgadmin4/docs/en_US -f Makefile
# Create additional builders to get all of the PostgreSQL utilities
#########################################################################
FROM postgres:9.4-alpine as pg94-builder
FROM postgres:9.5-alpine as pg95-builder
FROM postgres:9.6-alpine as pg96-builder
FROM postgres:10-alpine as pg10-builder
FROM postgres:11-alpine as pg11-builder
FROM postgres:12-alpine as pg12-builder
FROM alpine:3.10 as tool-builder
FROM alpine:3.11 as tool-builder
# Copy the PG binaries
COPY --from=pg94-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-9.4/
COPY --from=pg94-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-9.4/
COPY --from=pg94-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-9.4/
COPY --from=pg94-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-9.4/
COPY --from=pg95-builder /usr/local/bin/pg_dump /usr/local/pgsql/pgsql-9.5/
COPY --from=pg95-builder /usr/local/bin/pg_dumpall /usr/local/pgsql/pgsql-9.5/
COPY --from=pg95-builder /usr/local/bin/pg_restore /usr/local/pgsql/pgsql-9.5/
@@ -142,7 +136,7 @@ COPY --from=pg12-builder /usr/local/bin/psql /usr/local/pgsql/pgsql-12/
# Assemble everything into the final container.
#########################################################################
FROM python:3.7-alpine3.10
FROM python:3.8-alpine3.11
COPY --from=tool-builder /usr/local/pgsql /usr/local/
@@ -194,7 +188,7 @@ RUN groupadd -g 5050 pgadmin && \
chown pgadmin:pgadmin /var/log/pgadmin && \
touch /pgadmin4/config_distro.py && \
chown pgadmin:pgadmin /pgadmin4/config_distro.py && \
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/python3.7
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/python3.8
USER pgadmin
# Finish up
+1 -1
View File
@@ -254,7 +254,7 @@ REM Main build sequence Ends
CD "%WD%\runtime"
ECHO Running qmake...
CALL "%QMAKE%" || EXIT /B 1
CALL set "PGADMIN_PYTHON_DIR=%PYTHON_HOME%" && "%QMAKE%" || EXIT /B 1
ECHO Cleaning the build directory...
CALL %MAKE% clean || EXIT /B 1
+48 -62
View File
@@ -1,4 +1,4 @@
pgAdmin 4
pgAdmin 4
=========
pgAdmin 4 is a rewrite of the popular pgAdmin3 management tool for the
@@ -26,42 +26,46 @@ Building the Runtime
To build the runtime, the following packages must be installed:
- QT 4.6 or above (Use the VC++ build on Windows, not MinGW).
- Python 2.7 or 3.4+
- QT 5 (Use the VC++ build on Windows, not MinGW).
- Python 3.4+
Assuming both qmake and python-config are in the path:
An environment variable named PGADMIN_PYTHON_DIR must be set to the directory
in which Python has been installed, for example:
$ cd $PGADMIN4_SRC/runtime
$ qmake
Project MESSAGE: Building for QT5+...
Project MESSAGE: Building for Linux/Mac...
Project MESSAGE: Using /usr/bin/python-config
Project MESSAGE: Python2 detected.
$ make
...
- /usr
- /usr/local/python-3.8
- C:\Python38
To build the runtime in debug mode, use the option below with qmake
Assuming both qmake is in the path:
dpage@hal:~/git/pgadmin4$ cd runtime
dpage@hal:~/git/pgadmin4/runtime$ export PGADMIN_PYTHON_DIR=/opt/local
dpage@hal:~/git/pgadmin4/runtime$ qmake
Project MESSAGE: ==================================
Project MESSAGE: Configuring the pgAdmin 4 runtime.
Project MESSAGE: ==================================
Project MESSAGE: Qt version: 5
Project MESSAGE: Platform: macOS
Project MESSAGE: Python executable: /opt/local/bin/python3
Project MESSAGE: Python version: 3.8 (38)
Project MESSAGE: Python config: /opt/local/bin/python3-config
Project MESSAGE: CXXFLAGS: -pipe -stdlib=libc++ -I/opt/local/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8 -I/opt/local/Library/Frameworks/Python.framework/Versions/3.8/include/python3.8
Project MESSAGE: LDFLAGS: -stdlib=libc++ -L/opt/local/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/config-3.8-darwin -ldl -framework CoreFoundation
Project MESSAGE: LIBS: -lpython3.8 -ldl -framework CoreFoundation
dpage@hal:~/git/pgadmin4/runtime$ make
...
To build the runtime in debug mode, use the option below with qmake:
$ qmake CONFIG+=debug
To build the runtime in release mode, use the option below with qmake
To build the runtime in release mode, use the option below with qmake:
$ qmake CONFIG+=release
By default, the runtime application will be built in release mode.
On Linux, an executable called 'pgAdmin4' will be built, and on Mac OS X, an
app bundle called pgAdmin4.app will be created.
To build the runtime on a Windows system, export PYTHON_HOME and PYTHON_VERSION
variables in the System environment. Specify the PYTHON_VERSION with the major
and minor number. Do not specify micro level version.
For example, given a Python version of A.B.C; A - Major number, B - Minor
number, C - Micro level (Bug fix releases).
If Python version is 2.7.12 than specify PYTHON_VERSION=27
e.g. PYTHON_HOME=C:\Python27\
PYTHON_VERSION=27
On Linux, an executable called 'pgAdmin4' will be built, on Windows,
'pgAdmin4.exe', and on Mac OS X, an app bundle called pgAdmin4.app will be
created.
You can also use Qt Creator to build, develop and debug the runtime. Simply
open the $PGADMIN4_SRC/runtime/pgAdmin4.pro project file in Qt Creator and
@@ -88,10 +92,10 @@ Configuring the Python Environment
----------------------------------
In order to run the Python code, a suitable runtime environment is required.
Python versions - Python 2.7 or 3.4+ are currently supported. It is
recommended that a Python Virtual Environment is setup for this purpose,
rather than using the system Python environment. On Linux and Mac systems, the
process is fairly simple - adapt as required for your distribution:
Python version 3.4 and later are currently supported. It is recommended that a
Python Virtual Environment is setup for this purpose, rather than using the
system Python environment. On Linux and Mac systems, the process is fairly
simple - adapt as required for your distribution:
1) Install the virtualenv packages into the system Python environment
@@ -181,11 +185,10 @@ server or desktop mode, and access it from a web browser using the URL shown in
the terminal once pgAdmin has started up.
Setup of an environment on Windows is somewhat more complicated unfortunately,
largely due to the lack of a native compiler toolset. Thankfully, Microsoft
supply a free compiler specifically for Python 2.7 users. Download and install
it from:
largely due to the lack of a native compiler toolset. See the following wiki
page for more information on the compiler you may need:
https://www.microsoft.com/en-gb/download/details.aspx?id=44266
https://wiki.python.org/moin/WindowsCompilers
A blog detailing the setup of Virtual Environments on Windows can be found
here:
@@ -252,7 +255,7 @@ icon and select the Configuration option to open the configuration dialogue.
On a Linux/Mac system, the Python Path will typically consist of a single path
to the virtual environment's site-packages directory, e.g.
/Users/<USERNAME>/.virtualenvs/pgadmin4/lib/python2.7/site-packages
/Users/<USERNAME>/.virtualenvs/pgadmin4/lib/python3.8/site-packages
On Windows, multiple paths are likely to be required, e.g.
@@ -294,24 +297,7 @@ run:
(pgadmin4) $ make pip
On a Mac, build an application bundle in a disk image (DMG file) with:
(pgadmin4) $ make appbundle
Configure the framework.conf to match the QT and Python versions the app is
being built with:
$ cp $PGADMIN4_SRC/pkg/mac/framework.conf.in $PGADMIN4_SRC/pkg/mac/framework.conf
$ vi $PGADMIN4_SRC/pkg/mac/framework.conf
If you have an Apple code signing certificate, both the app bundle and disk
image can be automatically signed by configuring signing:
$ cp $PGADMIN4_SRC/pkg/mac/codesign.conf.in $PGADMIN4_SRC/pkg/mac/codesign.conf
$ vi $PGADMIN4_SRC/pkg/mac/codesign.conf
Edit the file as appropriate, ensuring the various version numbers are correct
and that the appropriate developer ID is specified.
To build the macOS AppBundle, please see pkg/mac/README.
On Windows, the InnoSetup tool is required to create an installer. Download the
Unicode version from:
@@ -320,16 +306,16 @@ http://www.jrsoftware.org/isdl.php
A number of environment variables may need to be set to enable the build script
to function. The defaults will usually work on a typical 64 bit system with
Qt 5.5.1, Python 2.7 and Visual Studio 2013. The examples below are for a
Qt 5.14.2, Python 3.8 and Visual Studio 2013. The examples below are for a
similar 32 bit system:
INNOTOOL=C:\Program Files\Inno Setup 5
PGDIR=C:\Program Files\PostgreSQL\10
PYTHON_DLL=C:\Windows\System32\Python27.dll
PYTHON_HOME=C:\Python27
PYTHON_VERSION=27
QTDIR=C:\Qt\5.9\msvc2013
VCDIR=C:\Program Files\Microsoft Visual Studio 12.0\VC
PGDIR=C:\Program Files\PostgreSQL\12
PYTHON_DLL=C:\Python38\Python38.dll
PYTHON_HOME=C:\Python38
PYTHON_VERSION=38
QTDIR=C:\Qt\5.14.2\msvc2015
VCDIR=C:\Program Files\Microsoft Visual Studio 14.0\VC
To build the installer:
+1 -5
View File
@@ -1,11 +1,7 @@
import os
import sys
import inspect
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
import builtins
# Ensure the global server mode is set.
builtins.SERVER_MODE = None
+1 -5
View File
@@ -14,11 +14,7 @@
import os
import sys
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
import builtins
# Ensure the global server mode is set.
builtins.SERVER_MODE = None
+1 -2
View File
@@ -17,7 +17,6 @@ maintenance functions to be executed. Multiple versions are included in the
following directories to allow use with different versions of the database
server:
* PostgreSQL 9.4: */usr/local/pgsql-9.4*
* PostgreSQL 9.5: */usr/local/pgsql-9.5*
* PostgreSQL 9.6: */usr/local/pgsql-9.6*
* PostgreSQL 10: */usr/local/pgsql-10*
@@ -60,7 +59,7 @@ expected paths are /certs/server.crt and /certs/server.key
Specify the local address that the servers listens on. The default should work
for most users - in IPv4-only environments, this may need to be set to
127.0.0.1.
0.0.0.0.
**PGADMIN_LISTEN_PORT**
+2 -2
View File
@@ -16,9 +16,9 @@ superuser privileges to use the debugger.
Before using the debugger, you must modify the *postgresql.conf* file, adding
the server-side debugger components to the the value of the
*shared_preload_libraries* parameter:
*shared_preload_libraries* parameter, for example:
shared_preload_libraries = '$libdir/*other_libraries*/plugin_debugger'
shared_preload_libraries = '$libdir/plugin_debugger'
After modifying the *shared_preload_libraries* parameter, restart the server to
apply the changes.
+9 -4
View File
@@ -45,10 +45,15 @@ file and modify the values for the following parameters:
entries, you should be able to authenticate by entering ‘admin’ in the 
*Email Address / Username* field and its corresponding password in the *Password* 
field."
"LDAP_SEARCH_BASE_DN","Specifies an element of the search request that works in
conjunction with the LDAP search scope to define the subtree of entries that
should be considered when processing the search request. You can use this parameter
for limiting the search request to a specific group of users."
"LDAP_SEARCH_BASE_DN","Specifies the distinguished name (DN) for the top-most user
directory that you want to search. You can use this parameter for limiting the search
request to a specific group of users. For example, if you want to search only within
the Organizational Unit named sales, you can define the value for LDAP_SEARCH_BASE_DN
parameter as following:
LDAP_SEARCH_BASE_DN = ‘ou=sales,dc=example,dc=com'
This is an optional parameter. If you do not specify any value for LDAP_SEARCH_BASE_DN,
then the value for LDAP_BASE_DN will be considered for the same."
"LDAP_SEARCH_FILTER","Defines the criteria to retrieve matching entries in an
LDAP search request. For example, LDAP_SEARCH_FILTER = '(objectclass=HR)’ setting
searches only for users having HR as their objectClass attribute."
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 185 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 119 KiB

+4 -3
View File
@@ -67,9 +67,10 @@ thresholds; use the *Table* tab and the *Toast Table* tab to customize values
for the table and the associated toast table. To change the default values:
* Move the *Custom auto-vacuum?* switch to the *Yes* position to perform custom
maintenance on the materialized view.
* Move the *Enabled?* switch to the *Yes* position to select values in the
*Vacuum table*. Provide values for each row in the *Value* column.
maintenance on the materialized view and to select values in the
*Vacuum table*. The *Vacuum Table* provides default values for maintenance
operations.
* Changing *Autovacuum enabled?* to *Not set* will reset autovacuum_enabled.
Click the *Security* tab to continue.
+1
View File
@@ -11,6 +11,7 @@ notes for it.
.. toctree::
:maxdepth: 1
release_notes_4_22
release_notes_4_21
release_notes_4_20
release_notes_4_19
+54
View File
@@ -0,0 +1,54 @@
************
Version 4.22
************
Release date: 2020-05-28
This release contains a number of bug fixes and new features since the release of pgAdmin4 4.21.
New features
************
| `Issue #5452 <https://redmine.postgresql.org/issues/5452>`_ - Added connected pgAdmin user and connection name in the log file.
| `Issue #5489 <https://redmine.postgresql.org/issues/5489>`_ - Show the startup log as well as the server log in the runtime's log viewer.
Housekeeping
************
| `Issue #5255 <https://redmine.postgresql.org/issues/5255>`_ - Implement Selenium Grid to run multiple tests across different browsers, operating systems, and machines in parallel.
| `Issue #5333 <https://redmine.postgresql.org/issues/5333>`_ - Improve code coverage and API test cases for Indexes.
| `Issue #5334 <https://redmine.postgresql.org/issues/5334>`_ - Improve code coverage and API test cases for the Rules module.
| `Issue #5335 <https://redmine.postgresql.org/issues/5335>`_ - Improve code coverage and API test cases for Triggers and Compound Triggers.
| `Issue #5443 <https://redmine.postgresql.org/issues/5443>`_ - Remove support for Python 2.
| `Issue #5444 <https://redmine.postgresql.org/issues/5444>`_ - Cleanup Python detection in the runtime project file.
| `Issue #5455 <https://redmine.postgresql.org/issues/5455>`_ - Refactor pgAdmin4.py so it can be imported and is a lot more readable.
| `Issue #5493 <https://redmine.postgresql.org/issues/5493>`_ - Search object UI improvements.
| `Issue #5525 <https://redmine.postgresql.org/issues/5525>`_ - Cleanup and refactor the macOS build scripts.
| `Issue #5552 <https://redmine.postgresql.org/issues/5552>`_ - Update dependencies in the Docker container.
| `Issue #5553 <https://redmine.postgresql.org/issues/5553>`_ - Remove PG 9.4 utilities from the Docker container as it's now out of support.
Bug fixes
*********
| `Issue #3694 <https://redmine.postgresql.org/issues/3694>`_ - Gracefully informed the user that the database is already connected when they click on "Connect Database...".
| `Issue #4033 <https://redmine.postgresql.org/issues/4033>`_ - Fixed an issue where clicking on the cross button of the alert box on the login page is not working.
| `Issue #4099 <https://redmine.postgresql.org/issues/4099>`_ - Fixed the SQL help issue for EDB Postgres Advanced Server.
| `Issue #4223 <https://redmine.postgresql.org/issues/4223>`_ - Ensure that maintenance job should be worked properly for indexes under a materialized view.
| `Issue #4279 <https://redmine.postgresql.org/issues/4279>`_ - Ensure that file browse "home" button should point to $HOME rather than /.
| `Issue #4840 <https://redmine.postgresql.org/issues/4840>`_ - Ensure that 'With OID' option should be disabled while taking backup of database server version 12 and above.
| `Issue #5001 <https://redmine.postgresql.org/issues/5001>`_ - Fixed invalid literal issue when removing the connection limit for the existing role.
| `Issue #5052 <https://redmine.postgresql.org/issues/5052>`_ - Fixed internal server error when clicking on Triggers -> 'Enable All' for partitions.
| `Issue #5398 <https://redmine.postgresql.org/issues/5398>`_ - Fixed generated SQL issue for auto vacuum options.
| `Issue #5422 <https://redmine.postgresql.org/issues/5422>`_ - Ensure that the dependencies tab shows correct information for Synonyms.
| `Issue #5434 <https://redmine.postgresql.org/issues/5434>`_ - Fixed an issue where the newly added table is not alphabetically added to the tree.
| `Issue #5440 <https://redmine.postgresql.org/issues/5440>`_ - Fixed list sorting issue in the schema diff tool.
| `Issue #5449 <https://redmine.postgresql.org/issues/5449>`_ - Fixed an issue while comparing the two identical schemas using the schema diff tool.
| `Issue #5450 <https://redmine.postgresql.org/issues/5450>`_ - Fixed an issue when renaming the column not added in the proper order.
| `Issue #5466 <https://redmine.postgresql.org/issues/5466>`_ - Correct ipv4 "all interfaces" address in the container docs, per Frank Limpert.
| `Issue #5469 <https://redmine.postgresql.org/issues/5469>`_ - Fixed an issue where select2 hover is inconsistent for the SSL field in create server dialog.
| `Issue #5473 <https://redmine.postgresql.org/issues/5473>`_ - Fixed post-login redirect location when running in server mode under a non-default root.
| `Issue #5480 <https://redmine.postgresql.org/issues/5480>`_ - Fixed an issue where the background job creation fails if there is only a version-specific python binary available in PATH.
| `Issue #5481 <https://redmine.postgresql.org/issues/5481>`_ - Fixed data truncation issue when updating the data of type character with length.
| `Issue #5487 <https://redmine.postgresql.org/issues/5487>`_ - Fixed an issue where if LDAP_SEARCH_BASE_DN is not set then, the value for LDAP_BASE_DN will be considered.
| `Issue #5496 <https://redmine.postgresql.org/issues/5496>`_ - Fixed an issue where clicking on Select All button, not selecting all the options in pgAgent job scheduler.
| `Issue #5503 <https://redmine.postgresql.org/issues/5503>`_ - Clarify and correct the docs on enabling the pl/debugger plugin on the server.
| `Issue #5510 <https://redmine.postgresql.org/issues/5510>`_ - Fixed Unicode decode error 'utf-8' codec can't decode byte.
+5 -2
View File
@@ -17,14 +17,17 @@ shortcut (default ALT+SHIFT+S).
The minimum pattern length are 3 characters. The search performed is
non-casesensitive and will find all objets whose name contains the pattern.
You can only search for object names.
You can only search for object names currently. Examples are: abc,
%ab%, ab%c, %%%, etc.
The result is presented in the grid with object name, object type and
the object tree path in the :ref:`browser <tree_control>`. You can double
click on a result row to select the object in the
:ref:`browser <tree_control>`. If the object is greyed out, this means that you
have not enabled those object types in the :ref:`preferences <preferences>`,
so you can't double click on it.
so you can't double click on it. You can click on the ellipsis appended to
the function and procedure names to see there arguments.
You can filter based on a particular object type by selecting one from the
object type dropdown. If the search button is hit when one of the object type
+2 -2
View File
@@ -485,10 +485,10 @@ thresholds; use the *Table* tab and the *Toast Table* tab to customize values
for the table and the associated toast table:
* Move the *Custom auto-vacuum?* switch to the *Yes* position to perform custom
maintenance on the table.
* Move the *Enabled?* switch to the *Yes* position to select values in the
maintenance on the table and to select values in the
*Vacuum table*. The *Vacuum Table* provides default values for maintenance
operations.
* Changing *Autovacuum enabled?* to *Not set* will reset autovacuum_enabled.
Provide a custom value in the *Value* column for each metric listed in the
*Label* column.
+115 -7
View File
@@ -1,6 +1,12 @@
This directory contains the build runner script for creating .DEB packages for
Debian and Ubuntu.
Supported platforms
===================
Debian 9 & 10
Ubuntu 16.04, 18.04, 19.04 & 19.10
Build configuration
===================
@@ -35,13 +41,115 @@ pgadmin4-web_<version>_<distro>_<distro_version>_<arch>.deb
The server mode setup script for configuring Apache HTTPD. Requires the
server package.
Supported platforms
===================
Building a repo
===============
Debian 9 & 10
Ubuntu 16.04, 18.04, 19.04 & 19.10
An APT repo can be created by building DEBs for the required platforms, moving
them into the required directory structure, and then running a number of
commands to create the required metadata. The pgAdmin repos use the following
structure (which doesn't entirely follow the normal structure for APT, but
does seem to work well unlike other attempts):
Warning
=======
<root>
bionic
dists
pgadmin4
InRelease
main
binary-all
Packages
Packages.gz
pgadmin4_4.21_all.deb
pgadmin4-web_4.21_all.deb
binary-amd64
Packages
Packages.gz
pgadmin4-desktop_4.21_amd64.deb
pgadmin4-server_4.21_amd64.deb
binary-i386
Packages
Packages.gz
Release
Release.gpg
Release.gz
buster
disco
eoan
focal
README
stretch
xenial
These scripts are experimental - use at your own risk!
Note that only the first branches are shown above; other branches (e.g. for
buster, disco etc. follow the structure shown for bionic.
Technically there are actually multiple repos here, one for each OS release.
Note also that the binary-i386 directories do not contain any packages as we're
not building 32bit packages for Linux. The directories and package indexes are
present though, to prevent warnings being emitted on amd64 machines which are
configured to support 32bit packages as well.
In order to sign the repositories you need to import your signing private key
into the gnupg2 keystore, for example:
gpg --import signing_key.priv
Once the files are in the right structure, we need to run a number of commands
to generate the metadata, and sign the relevant files using GPG (in APT, we
sign the repository indexes rather than the packages themselves.
To create the metadata, first we create a config file for the apt-ftparchive
program in $HOME/aptftp.conf (without the start/end markers):
----------
APT::FTPArchive::Release {
Origin "pgAdmin Development Team";
Label "pgAdmin 4";
Suite "pgadmin4";
Architectures "amd64 all";
Components "main";
Description "pgAdmin 4 - Development Tools for PostgreSQL";
};
Default {
Packages::Compress ". gzip bzip2";
Sources::Compress ". gzip bzip2";
Contents::Compress ". gzip bzip2";
};
----------
Next, we create the package indexes. Run the following command for each OS
release to be included (in the example, we're using bionic):
for ARCH in all amd64 i386; do cd <root>/bionic && apt-ftparchive packages -c=$HOME/aptftp.conf dists/pgadmin4/main/binary-${ARCH} > dists/pgadmin4/main/binary-${ARCH}/Packages && gzip -k dists/pgadmin4/main/binary-${ARCH}/Packages; done
Now we need to create the release file for each OS release (again, using bionic
in the example:
cd <root>/bionic/dists/pgadmin4 && apt-ftparchive release -c=$HOME/aptftp.conf . > Release && gzip -k Release
Finally, we can sign the release files. Replace <key name> with the email
address on your signing key:
cd <root>/bionic/dists/pgadmin4 && gpg -u <key name> -bao Release.gpg Release
cd <root>/bionic/dists/pgadmin4 && gpg -u <key name> --clear-sign --output InRelease Release
Note that it is important to run each command in the correct directory (hence
the cd commands) to ensure the relative paths are created correctly in the
indexes.
Repository Configuration
========================
pgAdmin repo configurations live in /etc/apt/sources.list.d/pgadmin4.list. The
file can be created with a command such as:
sudo sh -c 'echo "deb https://server.company.com/apt/$(lsb_release -cs) pgadmin4 main" > /etc/apt/sources.list.d/pgadmin4.list && apt update'
Assuming that <root> in the repository structure corresponds to
https://server.company.com/apt/ from the client's perspective.
If you have signed the repository, you'll also need to import the key on the
client. This is done as follows for the pgAdmin signing key; adjust the URL as
needed for your own:
curl http://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo apt-key add
+1 -1
View File
@@ -25,5 +25,5 @@ apt update
# Install pre-reqs
echo "Installing build pre-requisites..."
apt install -y build-essential python3-dev python3-venv python3-sphinx libpq-dev libffi-dev qt5-default nodejs yarn
apt install -y build-essential python3-dev python3-venv python3-sphinx python3-wheel libpq-dev libffi-dev qt5-default nodejs yarn
+2 -2
View File
@@ -107,9 +107,9 @@ _build_runtime() {
make clean
fi
if hash qmake-qt5 2>/dev/null; then
qmake-qt5
PGADMIN_PYTHON_DIR=/usr qmake-qt5
else
qmake
PGADMIN_PYTHON_DIR=/usr qmake
fi
make
mkdir -p "${DESKTOPROOT}/usr/${APP_NAME}/bin"
+8 -7
View File
@@ -47,12 +47,12 @@ fi
# Set SELinux up:
if [ ${IS_REDHAT} == 1 ]; then
echo "Configuring SELinux..."
setsebool -P httpd_can_network_connect 1
setsebool -P httpd_can_network_connect_db 1
semanage fcontext -a -t httpd_var_lib_t '/var/lib/pgadmin(/.*)?'
restorecon -R -v /var/lib/pgadmin
semanage fcontext -a -t httpd_log_t '/var/log/pgadmin(/.*)?'
restorecon -R -v /var/log/pgadmin
setsebool -P httpd_can_network_connect 1 1> /dev/null
setsebool -P httpd_can_network_connect_db 1 1> /dev/null
semanage fcontext -a -t httpd_var_lib_t '/var/lib/pgadmin(/.*)?' 1> /dev/null
restorecon -R -v /var/lib/pgadmin 1> /dev/null
semanage fcontext -a -t httpd_log_t '/var/log/pgadmin(/.*)?' 1> /dev/null
restorecon -R -v /var/log/pgadmin 1> /dev/null
fi
# Setup Apache on Debian/Ubuntu
@@ -97,7 +97,8 @@ else
if [ $? != 0 ]; then
echo "Error starting ${APACHE}. Please check the systemd logs"
else
echo "Apache successfully started. You can now start using pgAdmin 4 in web mode"
echo "Apache successfully started."
echo "You can now start using pgAdmin 4 in web mode at http://127.0.0.1/pgadmin4"
fi;;
* )
exit 1;;
+45
View File
@@ -0,0 +1,45 @@
Building pgAdmin4.dmg on Mac OS X
=================================
Required Packages (Either build the sources or get them from macports or
similar):
1. Python installation
- Python 3.4+ or above from https://www.python.org/
2. QT installation
- Qt 5 from http://www.qt.io/
3. PostgreSQL installation
- PostgreSQL 9.5 or above from http://www.postgresql.org/
Building:
1. If a value different from the default of /usr/local/python is required, set
the PGADMIN_PYTHON_DIR environment variable to the Python root installation
directory, e.g.
export PGADMIN_PYTHON_DIR=/opt/local
2. If a value different from the default of ~/Qt/5.13.2/clang_64, is required,
set the PGADMIN_QT_DIR environment variable to the QT root installation
directory, e.g.
export PGADMIN_QT_DIR=~/Qt/5.14.2/clang_64
3. If a value different from the default of /usr/local/pgsql is required, set
the PGADMIN_POSTGRES_DIR environment variable to the PostgreSQL installation
directory, e.g.
export PGADMIN_POSTGRES_DIR=/opt/local/pgsql
4. Copy framework.conf.in to framework.conf, and edit the values accordingly.
5. If you want to codesign the appbundle, copy codesign.conf.in to
codesign.conf and set the values accordingly.
6. To build, go to pgAdmin4 source root directory and execute "make appbundle".
This will create the python virtual environment and install all the required
python modules mentioned in the requirements file using pip, build the
runtime code and finally create the app bundle and the DMG in ./dist
directory.
-32
View File
@@ -1,32 +0,0 @@
Building pgAdmin4.dmg on Mac OS X
=================================
Required Packages (Either build the sources or get them from macports or similar):
1. Python installation
- Python 2.7 or 3.4+ or above from https://www.python.org/
2. QT installation
- Qt 4 or 5 from http://www.qt.io/
3. PostgreSQL installation
- PostgreSQL 9.1 or above from http://www.postgresql.org/
Building:
1. Set the PYTHON_HOME environment variable to the Python root installation directory, e.g.
export PYTHON_HOME=/System/Library/Frameworks/Python.framework/Versions/2.7
2. Set the QTDIR environment variable to the QT root installation directory, e.g.
export QTDIR=~/Qt/5.5/clang_64
3. Set the PGDIR environment variable to the PostgreSQL installation directory, e.g.
export PGDIR=/usr/local/pgsql
4. To build, go to pgAdmin4 source root directory and execute "make appbundle". This will
create the python virtual environment and install all the required python modules mentioned in the
requirements file using pip, build the runtime code and finally create the app bundle and the DMG
in ./dist directory
+382
View File
@@ -0,0 +1,382 @@
_setup_env() {
APP_RELEASE=`grep "^APP_RELEASE" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
APP_REVISION=`grep "^APP_REVISION" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
APP_NAME=`grep "^APP_NAME" web/config.py | cut -d"=" -f2 | sed "s/'//g" | sed 's/^ //'`
APP_LONG_VERSION=${APP_RELEASE}.${APP_REVISION}
APP_SHORT_VERSION=`echo ${APP_LONG_VERSION} | cut -d . -f1,2`
APP_SUFFIX=`grep "^APP_SUFFIX" web/config.py | cut -d"=" -f2 | sed 's/ //g' | sed "s/'//g"`
if [ ! -z ${APP_SUFFIX} ]; then
APP_LONG_VERSION=${APP_LONG_VERSION}-${APP_SUFFIX}
fi
BUNDLE_DIR="${BUILD_ROOT}/${APP_NAME}.app"
}
_cleanup() {
echo Cleaning up the old environment and app bundle...
rm -rf ${SOURCE_DIR}/runtime/*.app
rm -rf ${BUILD_ROOT}
rm -f ${DIST_ROOT}/*.dmg
}
_create_venv() {
PATH=${PGADMIN_POSTGRES_DIR}/bin:${PATH}
LD_LIBRARY_PATH=${PGADMIN_POSTGRES_DIR}/lib:${LD_LIBRARY_PATH}
test -d ${BUILD_ROOT} || mkdir ${BUILD_ROOT}
cd ${BUILD_ROOT}
${PYTHON_EXE} -m venv --copies venv
source venv/bin/activate
pip install --no-cache-dir --no-binary psycopg2 -r ${SOURCE_DIR}/requirements.txt
# Figure the source path for use when completing the venv
SOURCE_PYMODULES_PATH=$(dirname $("${PYTHON_EXE}" -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"))
# Figure the target path for use when completing the venv
# Use "python" here as we want the venv path
TARGET_PYMODULES_PATH=$(dirname $(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"))
# Copy in the additional system python modules
cp -R ${SOURCE_PYMODULES_PATH}/* "${TARGET_PYMODULES_PATH}/"
# Link the python<version> directory to python so that the private environment path is found by the application.
ln -s "$(basename ${TARGET_PYMODULES_PATH})" "${TARGET_PYMODULES_PATH}/../python"
# Remove tests
find venv -name "test" -type d -print0 | xargs -0 rm -rf
find venv -name "tests" -type d -print0 | xargs -0 rm -rf
}
_build_runtime() {
cd ${SOURCE_DIR}/runtime
if [ -f Makefile ]; then
make clean
fi
${QMAKE}
make
cp -r pgAdmin4.app "${BUNDLE_DIR}"
}
_build_docs() {
cd ${SOURCE_DIR}/docs/en_US
test -d "${BUNDLE_DIR}/Contents/Resources/docs/en_US" || mkdir -p "${BUNDLE_DIR}/Contents/Resources/docs/en_US"
cp -r _build/html "${BUNDLE_DIR}/Contents/Resources/docs/en_US/"
}
_complete_bundle() {
cd ${SCRIPT_DIR}
# Copy the binary utilities into place
mkdir -p "${BUNDLE_DIR}/Contents/SharedSupport/"
cp "${PGADMIN_POSTGRES_DIR}/bin/pg_dump" "${BUNDLE_DIR}/Contents/SharedSupport/"
cp "${PGADMIN_POSTGRES_DIR}/bin/pg_dumpall" "${BUNDLE_DIR}/Contents/SharedSupport/"
cp "${PGADMIN_POSTGRES_DIR}/bin/pg_restore" "${BUNDLE_DIR}/Contents/SharedSupport/"
cp "${PGADMIN_POSTGRES_DIR}/bin/psql" "${BUNDLE_DIR}/Contents/SharedSupport/"
# Replace the place holders with the current version
sed -e "s/PGADMIN_LONG_VERSION/${APP_LONG_VERSION}/g" -e "s/PGADMIN_SHORT_VERSION/${APP_SHORT_VERSION}/g" pgadmin.Info.plist.in > pgadmin.Info.plist
# copy Python private environment to app bundle
cp -PR ${BUILD_ROOT}/venv "${BUNDLE_DIR}/Contents/Resources/"
# Remove any TCL-related files that may cause us problems
find "${BUNDLE_DIR}/Contents/Resources/venv/" -name "_tkinter*" -print0 | xargs -0 rm -f
test -d "${BUNDLE_DIR}/Contents/Resources" || mkdir -p "${BUNDLE_DIR}/Contents/Resources"
# Create qt.conf so that app knows where the Plugins are present
cat >> "${BUNDLE_DIR}/Contents/Resources/qt.conf" << EOF
[Paths]
Plugins = PlugIns
EOF
test -d "${BUNDLE_DIR}/Contents/Frameworks" || mkdir -p "${BUNDLE_DIR}/Contents/Frameworks"
test -d "${BUNDLE_DIR}/Contents/PlugIns/platforms" || mkdir -p "${BUNDLE_DIR}/Contents/PlugIns/platforms"
test -d "${BUNDLE_DIR}/Contents/PlugIns/imageformats" || mkdir -p "${BUNDLE_DIR}/Contents/PlugIns/imageformats"
cp -f ${PGADMIN_QT_DIR}/plugins/platforms/libqcocoa.dylib "${BUNDLE_DIR}/Contents/PlugIns/platforms"
cp -f ${PGADMIN_QT_DIR}/plugins/imageformats/libqsvg.dylib "${BUNDLE_DIR}/Contents/PlugIns/imageformats"
cp -f ${PGADMIN_POSTGRES_DIR}/lib/libpq.5.dylib "${BUNDLE_DIR}/Contents/Frameworks"
local todo todo_old fw_relpath lib lib_bn
pushd "${BUNDLE_DIR}" > /dev/null
# We skip nested apps here - those are treated specially
todo=$(file `find ./ -perm +0111 ! -type d ! -path "*.app/*" ! -name "*.app"` | grep -E "Mach-O 64-bit" | awk -F ':| ' '{ORS=" "; print $1}')
echo "Found executables: ${todo}"
while test "${todo}" != ""; do
todo_old=${todo} ;
todo="" ;
for todo_obj in ${todo_old}; do
echo "Post-processing: ${todo_obj}"
# Figure out the relative path from todo_obj to Contents/Frameworks
fw_relpath=$(echo "${todo_obj}" | sed -n 's|^\(\.//*\)\(\([^/][^/]*/\)*\)[^/][^/]*$|\2|gp' | sed -n 's|[^/][^/]*/|../|gp')"Contents/Frameworks"
fw_relpath_old=${fw_relpath}
# Find all libraries $todo_obj depends on, but skip system libraries
for lib in $(otool -L ${todo_obj} | grep "Qt\|dylib\|Frameworks\|PlugIns" | grep -v ":" | sed 's/(.*//' | egrep -v '(/usr/lib)|(/System)|@executable_path@'); do
if echo ${lib} | grep "PlugIns\|libqcocoa" > /dev/null; then
lib_loc="Contents/PlugIns/platforms"
elif echo ${lib} | grep "PlugIns\|libqsvg" > /dev/null; then
lib_loc="Contents/PlugIns/imageformats"
elif echo ${lib} | grep "Qt" > /dev/null; then
qtfw_path="$(dirname ${lib} | sed 's|.*\(Qt.*framework\)|\1|')"
lib_loc="Contents/Frameworks/${qtfw_path}"
if [ "$(basename ${todo_obj})" = "${lib}" ]; then
lib_loc="$(dirname ${todo_obj})"
qtfw_path=$(echo ${lib_loc} | sed 's/Contents\/Frameworks\///')
fi
elif echo ${lib} | grep "Python" > /dev/null; then
pyfw_path="$(dirname ${lib} | sed 's|.*\(Python.*framework\)|\1|')"
lib_loc="Contents/Frameworks/${pyfw_path}"
if [ "$(basename ${todo_obj})" = "${lib}" ]; then
lib_loc="$(dirname ${todo_obj})"
pyfw_path=$(echo ${lib_loc} | sed 's/Contents\/Frameworks\///')
fi
else
lib_loc="Contents/Frameworks"
fi
lib_bn="$(basename "${lib}")" ;
if ! test -f "${lib_loc}/${lib_bn}"; then
target_file=""
target_path=""
echo "Adding symlink: ${lib_bn} (because of: ${todo_obj})"
# Copy the QT and Python framework
if echo ${lib} | grep Qt > /dev/null ; then
test -d ${lib_loc} || mkdir -p ${lib_loc}
echo Copying -R ${PGADMIN_QT_DIR}/lib/${qtfw_path}/${lib_bn} to ${lib_loc}/
cp ${PGADMIN_QT_DIR}/lib/${qtfw_path}/${lib_bn} ${lib_loc}/
elif echo ${lib} | grep Python > /dev/null ; then
test -d ${lib_loc} || mkdir -p ${lib_loc}
cp -R "${lib}" "${lib_loc}/${lib_bn}"
else
cp -R "${lib}" "${lib_loc}/${lib_bn}"
fi
if ! test -L "${lib_loc}/${lib_bn}"; then
chmod 755 "${lib_loc}/${lib_bn}"
else
target_file=$(readlink "${lib}")
target_path=$(dirname "${lib}")/${target_file}
echo "Adding symlink target: ${target_path}"
cp "${target_path}" "${lib_loc}/${target_file}"
chmod 755 "${lib_loc}/${target_file}"
fi
echo "Rewriting ID in ${lib_loc}/${lib_bn} to ${lib_bn}"
install_name_tool -id "${lib_bn}" "${lib_loc}/${lib_bn}"
todo="${todo} ./${lib_loc}/${lib_bn}"
fi
if echo ${lib} | grep Qt > /dev/null ; then
fw_relpath="${fw_relpath}/${qtfw_path}"
fi
if echo ${lib} | grep Python > /dev/null ; then
fw_relpath="${fw_relpath}/${pyfw_path}"
fi
chmod +w ${todo_obj}
echo "Rewriting library ${lib} to @loader_path/${fw_relpath}/${lib_bn} in ${todo_obj}"
install_name_tool -change "${lib}" "@loader_path/${fw_relpath}/${lib_bn}" "${todo_obj}"
install_name_tool -change "${target_path}" "@loader_path/${fw_relpath}/${target_file}" "${todo_obj}"
fw_relpath="${fw_relpath_old}"
done
done
done
# Fix the rpaths for psycopg module
find "${BUNDLE_DIR}/Contents/Resources/venv/" -name _psycopg.so -print0 | xargs -0 install_name_tool -change libpq.5.dylib @loader_path/../../../../../../Frameworks/libpq.5.dylib
find "${BUNDLE_DIR}/Contents/Resources/venv/" -name _psycopg.so -print0 | xargs -0 install_name_tool -change libssl.1.0.0.dylib @loader_path/../../../../../../Frameworks/libssl.1.0.0.dylib
find "${BUNDLE_DIR}/Contents/Resources/venv/" -name _psycopg.so -print0 | xargs -0 install_name_tool -change libcrypto.1.0.0.dylib @loader_path/../../../../../../Frameworks/libcrypto.1.0.0.dylib
echo "App completed: ${BUNDLE_DIR}"
popd > /dev/null
pushd ${SOURCE_DIR}/web > /dev/null
yarn install
yarn run bundle
curl https://curl.haxx.se/ca/cacert.pem -o cacert.pem -s
popd > /dev/null
# copy the web directory to the bundle as it is required by runtime
cp -r ${SOURCE_DIR}/web "${BUNDLE_DIR}/Contents/Resources/"
cd "${BUNDLE_DIR}/Contents/Resources/web"
rm -f pgadmin4.db config_local.*
rm -rf karma.conf.js package.json node_modules/ regression/ tools/ pgadmin/static/js/generated/.cache
find . -name "tests" -type d -print0 | xargs -0 rm -rf
find . -name "feature_tests" -type d -print0 | xargs -0 rm -rf
find . -name ".DS_Store" -print0 | xargs -0 rm -f
echo "SERVER_MODE = False" > config_distro.py
echo "HELP_PATH = '../../../docs/en_US/html/'" >> config_distro.py
echo "DEFAULT_BINARY_PATHS = {" >> config_distro.py
echo " 'pg': '\$DIR/../../SharedSupport'," >> config_distro.py
echo " 'ppas': ''" >> config_distro.py
echo "}" >> config_distro.py
# Remove the .pyc files if any
find "${BUNDLE_DIR}" -name "*.pyc" -print0 | xargs -0 rm -f
}
_framework_config() {
# Get the config
source ${SCRIPT_DIR}/framework.conf
echo Reorganising the framework structure...
# Create "Current" and "Current/Resources" inside each of the framework dirs
find "${BUNDLE_DIR}/Contents/Frameworks"/*framework -type d -name "Versions" | while read -r framework_dir; do
pushd "${framework_dir}" > /dev/null
# Create framework 'Current' soft link
VERSION_NUMBER=`ls -1`
ln -s ${VERSION_NUMBER} Current
# Create "Resources" subdirectory
if [ ! -d Current/Resources ]; then
mkdir Current/Resources
fi
popd > /dev/null
done
# Stuff for Qt framework files only
find "${BUNDLE_DIR}/Contents/Frameworks" -type d -name "Qt*framework" | while read -r framework_dir; do
pushd "${framework_dir}" > /dev/null
# Create soft link to the framework binary
ln -s Versions/Current/Qt*
# Create soft link to the framework Resources dir
ln -s Versions/Current/Resources
# Create the Info.plist files
MYNAME=`ls -1 Qt*`
if [ -f Resources/Info.plist ]; then
chmod +w Resources/Info.plist
fi
sed 's/__SHORT_VERSION__/${QT_SHORT_VERSION}/' "${SCRIPT_DIR}/Info.plist-template_Qt5" | sed 's/__FULL_VERSION__/${QT_FULL_VERSION}/' | sed "s/__FRAMEWORK_NAME__/${MYNAME}/" > "Resources/Info.plist"
popd > /dev/null
done
# Same thing, but specific to the Python framework dir
find "${BUNDLE_DIR}/Contents/Frameworks" -type d -name "P*framework" | while read -r framework_dir; do
pushd "${framework_dir}" > /dev/null
# Create soft link to the framework binary
ln -s Versions/Current/Py*
# Create soft link to the framework Resources dir
ln -s Versions/Current/Resources
# Create the Info.plist file
MYNAME=`ls -1 Py*`
sed 's/__SHORT_VERSION__/${PYTHON_SHORT_VERSION}/' "${SCRIPT_DIR}/Info.plist-template_Python" | sed 's/__FULL_VERSION__/${PYTHON_FULL_VERSION}/' | sed "s/__FRAMEWORK_NAME__/${MYNAME}/" > "Resources/Info.plist"
popd > /dev/null
done
}
_codesign_binaries() {
if [ ${CODESIGN} -eq 0 ]; then
return
fi
if [ -z "${DEVELOPER_ID}" ] ; then
echo "Developer ID Application not found in codesign.conf" >&2
exit 1
fi
if [ -z "${DEVELOPER_BUNDLE_ID}" ]; then
echo "Developer Bundle Identifier not found in codesign.conf" >&2
fi
echo Signing ${BUNDLE_DIR} binaries...
IFS=$'\n'
for i in $(find "${BUNDLE_DIR}" -type f -perm +111 -exec file "{}" \; | grep -E "Mach-O executable|Mach-O 64-bit executable|Mach-O 64-bit bundle" | awk -F":| \\\(" '{print $1}' | uniq)
do
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "$i"
done
echo Signing ${BUNDLE_DIR} libraries...
for i in $(find "${BUNDLE_DIR}" -type f -name "*.dylib*")
do
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "$i"
done
}
_codesign_bundle() {
if [ ${CODESIGN} -eq 0 ]; then
return
fi
# Sign the .app
echo Signing ${BUNDLE_DIR}...
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "${BUNDLE_DIR}"
# Verify it worked
echo Verifying the signature...
codesign --verify --verbose --deep --force "${BUNDLE_DIR}"
echo ${BUNDLE_DIR} successfully signed.
}
_create_dmg() {
# move to the directory where we want to create the DMG
test -d ${DIST_ROOT} || mkdir ${DIST_ROOT}
cd ${DIST_ROOT}
DMG_LICENCE=./../pkg/mac/licence.rtf
DMG_VOLUME_NAME=${APP_NAME}
DMG_NAME=`echo ${DMG_VOLUME_NAME} | sed 's/ //g' | awk '{print tolower($0)}'`
DMG_IMAGE=${DMG_NAME}-${APP_LONG_VERSION}.dmg
DMG_DIR=./${DMG_IMAGE}.src
if test -e "${DMG_DIR}"; then
echo "Directory ${DMG_DIR} already exists. Please delete it manually." >&2
exit 1
fi
echo "Cleaning up"
rm -f "${DMG_IMAGE}"
mkdir "${DMG_DIR}"
echo "Copying data into temporary directory"
cp -R "${BUNDLE_DIR}" "${DMG_DIR}"
echo "Creating image"
hdiutil create -quiet -srcfolder "$DMG_DIR" -fs HFS+ -format UDZO -volname "${DMG_VOLUME_NAME}" -ov "${DMG_IMAGE}"
rm -rf "${DMG_DIR}"
echo Attaching License to image...
python ${SCRIPT_DIR}/dmg-license.py "${DMG_IMAGE}" "${DMG_LICENCE}" -c bz2
}
_codesign_dmg() {
if [ ${CODESIGN} -eq 0 ]; then
return
fi
DMG_VOLUME_NAME=${APP_NAME}
DMG_NAME=`echo ${DMG_VOLUME_NAME} | sed 's/ //g' | awk '{print tolower($0)}'`
DMG_IMAGE=${DIST_ROOT}/${DMG_NAME}-${APP_LONG_VERSION}.dmg
if ! test -f "${DMG_IMAGE}" ; then
echo "${DMG_IMAGE} is no disk image!" >&2
exit 1
fi
# Sign the .app
echo Signing ${DMG_IMAGE}...
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "${DMG_IMAGE}"
# Verify it worked
echo Verifying the signature...
codesign --verify --verbose --force "${DMG_IMAGE}"
echo ${DMG_IMAGE} successfully signed.
}
+45 -250
View File
@@ -2,13 +2,19 @@
# Build script to create Mac App Bundle and DMG for pgAdmin4 runtime
export WD=$(cd `dirname $0` && pwd)
export SOURCEDIR=${WD}/../..
export BUILDROOT=${WD}/../../mac-build
export DISTROOT=${WD}/../../dist
export VIRTUALENV=venv
# Exit when any command fails
set -e -E
if [ ! -f ${SOURCEDIR}/pkg/mac/framework.conf ]; then
# Debugging shizz
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
trap 'if [ $? -ne 0 ]; then echo "\"${last_command}\" command filed with exit code $?."; fi' EXIT
SCRIPT_DIR=$(cd `dirname $0` && pwd)
SOURCE_DIR=$(realpath ${SCRIPT_DIR}/../..)
BUILD_ROOT=$(realpath ${SCRIPT_DIR}/../..)/mac-build
DIST_ROOT=$(realpath ${SCRIPT_DIR}/../..)/dist
if [ ! -f ${SCRIPT_DIR}/framework.conf ]; then
echo
echo "Error: pkg/mac/framework.conf not found!"
echo "Copy pkg/mac/framework.conf.in to pkg/mac/framework.conf and edit as required for the current system."
@@ -16,272 +22,61 @@ if [ ! -f ${SOURCEDIR}/pkg/mac/framework.conf ]; then
exit 1
fi
export SYSTEM_PYTHON=0
if [ "x${PYTHON_HOME}" == "x" ]; then
echo "PYTHON_HOME not set. Setting it to default"
export PYTHON_HOME=/System/Library/Frameworks/Python.framework/Versions/2.7
export PYTHON_VERSION=27
export SYSTEM_PYTHON=1
CODESIGN=1
if [ ! -f ${SCRIPT_DIR}/codesign.conf ]; then
echo
echo "******************************************************************"
echo "* ${SCRIPT_DIR}/codesign.conf not found. NOT signing the binaries."
echo "******************************************************************"
echo
CODESIGN=0
sleep 5
else
source ${SCRIPT_DIR}/codesign.conf
fi
if [ "x${PGADMIN_PYTHON_DIR}" == "x" ]; then
echo "PGADMIN_PYTHON_DIR not set. Setting it to the default: /usr/local/python"
export PGADMIN_PYTHON_DIR=/usr/local/python
fi
PYTHON_EXE=${PGADMIN_PYTHON_DIR}/bin/python3
# Check if Python is working and calculate PYTHON_VERSION
if ${PYTHON_HOME}/bin/python2 -V > /dev/null 2>&1; then
export PYTHON_VERSION=`${PYTHON_HOME}/bin/python2 -V 2>&1 | awk '{print $2}' | cut -d"." -f1-2 | sed 's/\.//'`
elif ${PYTHON_HOME}/bin/python3 -V > /dev/null 2>&1; then
export PYTHON_VERSION=`${PYTHON_HOME}/bin/python3 -V 2>&1 | awk '{print $2}' | cut -d"." -f1-2 | sed 's/\.//'`
if ${PYTHON_EXE} -V > /dev/null 2>&1; then
PYTHON_VERSION=`${PYTHON_EXE} -V 2>&1 | awk '{print $2}' | cut -d"." -f1-2 | sed 's/\.//'`
else
echo "Error: Python installation missing!"
exit 1
fi
if [ "${PYTHON_VERSION}" -gt "37" -a "${PYTHON_VERSION}" -lt "27" ]; then
echo "Python version not supported"
if [ "${PYTHON_VERSION}" -gt "38" ] && [ "${PYTHON_VERSION}" -lt "34" ]; then
echo "Python version not supported."
exit 1
fi
if [ "${PYTHON_VERSION}" -ge "30" ]; then
export PYTHON=${PYTHON_HOME}/bin/python3
export PIP=pip3
else
export PYTHON=${PYTHON_HOME}/bin/python2
export PIP=pip
if [ "x${PGADMIN_QT_DIR}" == "x" ]; then
echo "PGADMIN_QT_DIR not set. Setting it to the default: ~/Qt/5.13.2/clang_64"
export PGADMIN_QT_DIR=~/Qt/5.13.2/clang_64
fi
if [ "x${QTDIR}" == "x" ]; then
echo "QTDIR not set. Setting it to default"
export QTDIR=~/Qt/5.8/clang_64
fi
export QMAKE=${QTDIR}/bin/qmake
QMAKE=${PGADMIN_QT_DIR}/bin/qmake
if ! ${QMAKE} --version > /dev/null 2>&1; then
echo "Error: qmake not found. QT installation is not present or incomplete."
exit 1
fi
if [ "x${PGDIR}" == "x" ]; then
echo "PGDIR not set. Setting it to default"
export PGDIR=/usr/local/pgsql
if [ "x${PGADMIN_POSTGRES_DIR}" == "x" ]; then
echo "PGADMIN_POSTGRES_DIR not set. Setting it to the default: /usr/local/pgsql"
export PGADMIN_POSTGRES_DIR=/usr/local/pgsql
fi
_get_version() {
export APP_RELEASE=`grep "^APP_RELEASE" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
export APP_REVISION=`grep "^APP_REVISION" web/config.py | cut -d"=" -f2 | sed 's/ //g'`
export APP_NAME=`grep "^APP_NAME" web/config.py | cut -d"=" -f2 | sed "s/'//g" | sed 's/^ //'`
export APP_BUNDLE_NAME=${APP_NAME}.app
export APP_LONG_VERSION=${APP_RELEASE}.${APP_REVISION}
export APP_SHORT_VERSION=`echo ${APP_LONG_VERSION} | cut -d . -f1,2`
export APP_SUFFIX=`grep "^APP_SUFFIX" web/config.py | cut -d"=" -f2 | sed 's/ //g' | sed "s/'//g"`
if [ ! -z ${APP_SUFFIX} ]; then
export APP_LONG_VERSION=${APP_LONG_VERSION}-${APP_SUFFIX}
fi
}
source ${SCRIPT_DIR}/build-functions.sh
_cleanup() {
echo "Cleaning up the old environment and app bundle"
rm -rf ${SOURCEDIR}/runtime/pgAdmin4.app
rm -rf ${BUILDROOT}
rm -f ${DISTROOT}/pgadmin4*.dmg
}
_create_python_virtualenv() {
export PATH=${PGDIR}/bin:${PATH}
export LD_LIBRARY_PATH=${PGDIR}/lib:${LD_LIBRARY_PATH}
test -d ${BUILDROOT} || mkdir ${BUILDROOT} || exit 1
cd ${BUILDROOT}
if [ ${SYSTEM_PYTHON} -eq 1 ]; then
test -d ${VIRTUALENV} || virtualenv -p ${PYTHON} ${VIRTUALENV} || exit 1
else
test -d ${VIRTUALENV} || virtualenv -p ${PYTHON} --always-copy ${VIRTUALENV} || exit 1
fi
source ${VIRTUALENV}/bin/activate
${PIP} install --no-cache-dir --no-binary psycopg2 -r ${SOURCEDIR}/requirements.txt || { echo PIP install failed. Please resolve the issue and rerun the script; exit 1; }
# Figure out some paths for use when completing the venv
# Use "python" here as we want the venv path
export PYMODULES_PATH=`python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"`
export DIR_PYMODULES_PATH=`dirname ${PYMODULES_PATH}`
# Use $PYTHON here as we want the system path
export PYSYSLIB_PATH=`${PYTHON} -c "import sys; print('%s/lib/python%d.%.d' % (sys.prefix, sys.version_info.major, sys.version_info.minor))"`
# Symlink in the rest of the Python libs. This is required because the runtime
# will clear PYTHONHOME for safety, which has the side-effect of preventing
# it from finding modules that are not explicitly included in the venv
cd ${DIR_PYMODULES_PATH}
# Files
for FULLPATH in ${PYSYSLIB_PATH}/*.py; do
FILE=${FULLPATH##*/}
if [ ! -e ${FILE} ]; then
if [ ${SYSTEM_PYTHON} -eq 1 ]; then
ln -s ${FULLPATH} ${FILE}
else
cp ${FULLPATH} ${FILE}
fi
fi
done
# Paths
for FULLPATH in ${PYSYSLIB_PATH}/*/; do
FULLPATH=${FULLPATH%*/}
FILE=${FULLPATH##*/}
if [ ! -e ${FILE} ]; then
if [ ${SYSTEM_PYTHON} -eq 1 ]; then
ln -s ${FULLPATH} ${FILE}
else
cp -R ${FULLPATH} ${FILE}
fi
fi
done
# Remove tests
cd site-packages
find . -name "test" -type d -print0 | xargs -0 rm -rf
find . -name "tests" -type d -print0 | xargs -0 rm -rf
# Link the python<version> directory to python so that the private environment path is found by the application.
if test -d ${DIR_PYMODULES_PATH}; then
ln -s $(basename ${DIR_PYMODULES_PATH}) ${DIR_PYMODULES_PATH}/../python
fi
}
_build_runtime() {
_create_python_virtualenv || exit 1
cd ${SOURCEDIR}/runtime
make clean
${QMAKE} || { echo qmake failed; exit 1; }
make || { echo make failed; exit 1; }
cp -r pgAdmin4.app "${BUILDROOT}/${APP_BUNDLE_NAME}"
}
_build_doc() {
cd ${SOURCEDIR}/docs/en_US
test -d "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources" || "mkdir -p ${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources"
test -d "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/docs/en_US" || mkdir -p "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/docs/en_US"
cp -r _build/html "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/docs/en_US/" || exit 1
}
_complete_bundle() {
cd ${SOURCEDIR}/pkg/mac
# Copy the binary utilities into place
mkdir -p "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/SharedSupport/" || exit 1
cp "${PGDIR}/bin/pg_dump" "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/SharedSupport/" || exit 1
cp "${PGDIR}/bin/pg_dumpall" "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/SharedSupport/" || exit 1
cp "${PGDIR}/bin/pg_restore" "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/SharedSupport/" || exit 1
cp "${PGDIR}/bin/psql" "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/SharedSupport/" || exit 1
# Replace the place holders with the current version
sed -e "s/PGADMIN_LONG_VERSION/${APP_LONG_VERSION}/g" -e "s/PGADMIN_SHORT_VERSION/${APP_SHORT_VERSION}/g" pgadmin.Info.plist.in > pgadmin.Info.plist
# copy Python private environment to app bundle
cp -PR ${BUILDROOT}/${VIRTUALENV} "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/" || exit 1
if [ ${SYSTEM_PYTHON} -eq 1 ]; then
# remove the python bin and include from app bundle as it is not needed
rm -rf "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/${VIRTUALENV}/bin" "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/${VIRTUALENV}/include"
rm -rf "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/${VIRTUALENV}/.Python"
fi
# Remove any TCL-related files that may cause us problems
find "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/${VIRTUALENV}/" -name "_tkinter*" -print0 | xargs -0 rm -f
# run complete-bundle to copy the dependent libraries and frameworks and fix the rpaths
./complete-bundle.sh "${BUILDROOT}/${APP_BUNDLE_NAME}" || { echo complete-bundle.sh failed; exit 1; }
pushd ${SOURCEDIR}/web
yarn install || exit 1
yarn run bundle || exit 1
curl https://curl.haxx.se/ca/cacert.pem -o cacert.pem -s || { echo Failed to download cacert.pem; exit 1; }
popd
# copy the web directory to the bundle as it is required by runtime
cp -r ${SOURCEDIR}/web "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/" || exit 1
cd "${BUILDROOT}/${APP_BUNDLE_NAME}/Contents/Resources/web"
rm -f pgadmin4.db config_local.*
rm -rf karma.conf.js package.json node_modules/ regression/ tools/ pgadmin/static/js/generated/.cache
find . -name "tests" -type d -print0 | xargs -0 rm -rf
find . -name "feature_tests" -type d -print0 | xargs -0 rm -rf
find . -name ".DS_Store" -print0 | xargs -0 rm -f
echo "SERVER_MODE = False" > config_distro.py
echo "HELP_PATH = '../../../docs/en_US/html/'" >> config_distro.py
echo "DEFAULT_BINARY_PATHS = {" >> config_distro.py
echo " 'pg': '\$DIR/../../SharedSupport'," >> config_distro.py
echo " 'ppas': ''" >> config_distro.py
echo "}" >> config_distro.py
# Remove the .pyc files if any
cd "${BUILDROOT}/${APP_BUNDLE_NAME}"
find . -name *.pyc -print0 | xargs -0 rm -f
}
_framework_config() {
cd ${SOURCEDIR}/pkg/mac
./framework-config.sh "${BUILDROOT}/${APP_BUNDLE_NAME}" || { echo "framework-config.sh failed"; exit 1; }
}
_codesign_binaries() {
cd ${SOURCEDIR}/pkg/mac
if [ ! -f codesign.conf ]; then
echo
echo "******************************************************************"
echo "* codesign.conf not found. NOT signing the binaries."
echo "******************************************************************"
echo
sleep 5
return
fi
./codesign-binaries.sh "${BUILDROOT}/${APP_BUNDLE_NAME}" || { echo codesign-binaries.sh failed; exit 1; }
}
_codesign_bundle() {
cd ${SOURCEDIR}/pkg/mac
if [ ! -f codesign.conf ]; then
echo
echo "******************************************************************"
echo "* codesign.conf not found. NOT signing the bundle."
echo "******************************************************************"
echo
sleep 5
return
fi
./codesign-bundle.sh "${BUILDROOT}/${APP_BUNDLE_NAME}" || { echo codesign-bundle.sh failed; exit 1; }
}
_create_dmg() {
cd ${SOURCEDIR}
./pkg/mac/create-dmg.sh || { echo create-dmg.sh failed; exit 1; }
# Clean the mac-build/ on successful build
rm -rf ${BUILDROOT}/*
}
_codesign_dmg() {
cd ${SOURCEDIR}/pkg/mac
if [ ! -f codesign.conf ]; then
echo
echo "******************************************************************"
echo "* codesign.conf not found. NOT signing the disk image."
echo "******************************************************************"
echo
sleep 5
return
fi
./codesign-dmg.sh || { echo codesign-bundle.sh failed; exit 1; }
}
_get_version || { echo Could not get versioning; exit 1; }
_setup_env
_cleanup
_build_runtime || { echo Runtime build failed; exit 1; }
_build_doc
_create_venv
_build_runtime
_build_docs
_complete_bundle
_framework_config
_codesign_binaries
-36
View File
@@ -1,36 +0,0 @@
#!/bin/sh
BUNDLE="$1"
if ! test -d "${BUNDLE}" ; then
echo "${BUNDLE} is no bundle!" >&2
exit 1
fi
# Get the config
source codesign.conf
if [ -z "${DEVELOPER_ID}" ] ; then
echo "Developer ID Application not found in codesign.conf" >&2
exit 1
fi
if [ -z "${DEVELOPER_BUNDLE_ID}" ]; then
echo "Developer Bundle Identifier not found in codesign.conf" >&2
fi
echo Signing ${BUNDLE} binaries
IFS=$'\n'
for i in $(find "${BUNDLE}" -type f)
do
file "${i}" | grep -E "Mach-O executable|Mach-O 64-bit executable|Mach-O 64-bit bundle"
if [ $? -eq 0 ] ; then
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "$i"
fi
done
echo Signing ${BUNDLE} libraries
for i in $(find "${BUNDLE}" -type f -name "*.dylib*")
do
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "$i"
done
-26
View File
@@ -1,26 +0,0 @@
#!/bin/sh
BUNDLE="$1"
if ! test -d "${BUNDLE}" ; then
echo "${BUNDLE} is no bundle!" >&2
exit 1
fi
# Get the config
source codesign.conf
# Sign the .app
echo Signing ${BUNDLE}
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "${BUNDLE}"
# Verify it worked
echo Verifying the signature
codesign --verify --verbose --deep --force "${BUNDLE}"
RETURN_STATUS=$?
if [ ${RETURN_STATUS} -ne 0 ]; then
echo Code signing did not work, check the log
exit 1
else
echo ${BUNDLE} successfully signed
fi
-30
View File
@@ -1,30 +0,0 @@
#!/bin/bash
DMG_VOLUME_NAME=${APP_NAME}
DMG_NAME=`echo ${DMG_VOLUME_NAME} | sed 's/ //g' | awk '{print tolower($0)}'`
DMG_IMAGE=${DISTROOT}/${DMG_NAME}-${APP_LONG_VERSION}.dmg
if ! test -f "${DMG_IMAGE}" ; then
echo "${DMG_IMAGE} is no disk image!" >&2
exit 1
fi
# Get the config
source codesign.conf
SCRIPT_DIR=`pwd`
# Sign the .app
echo Signing ${DMG_IMAGE}
codesign --deep --force --verify --verbose --timestamp --options runtime -i "${DEVELOPER_BUNDLE_ID}" --sign "${DEVELOPER_ID}" "${DMG_IMAGE}"
# Verify it worked
echo Verifying the signature
codesign --verify --verbose --force "${DMG_IMAGE}"
RETURN_STATUS=$?
if [ ${RETURN_STATUS} -ne 0 ]; then
echo ERROR: Code signing did not work
exit 1
else
echo ${DMG_IMAGE} successfully signed
fi
+1 -1
View File
@@ -1,5 +1,5 @@
# In order to enable codesigning of the Mac Appbundle, copy this file to
# codesign.conf, and edit the value below to reflect your developer ID
# codesign.conf, and edit the values below to reflect your developer ID.
DEVELOPER_ID="Developer ID Application: My Name (12345ABCD)"
DEVELOPER_BUNDLE_ID="Developer Bundle Identifier (pgadmin4-4)"
-146
View File
@@ -1,146 +0,0 @@
#!/bin/sh
bundle="$1"
if ! test -d "$bundle" ; then
echo "${bundle} is no bundle!" >&2
exit 1
fi
if test -z ${QTDIR} ; then
echo "QTDIR environment variable not set"
exit 1
else
echo "QTDIR=${QTDIR}"
fi
test -d "${bundle}/Contents/Resources" || mkdir -p "${bundle}/Contents/Resources" || exit 1
# Create qt.conf so that app knows where the Plugins are present
cat >> "${bundle}/Contents/Resources/qt.conf" << EOF
[Paths]
Plugins = PlugIns
EOF
test -d "${bundle}/Contents/Frameworks" || mkdir -p "${bundle}/Contents/Frameworks" || exit 1
test -d "${bundle}/Contents/PlugIns/platforms" || mkdir -p "${bundle}/Contents/PlugIns/platforms" || exit 1
test -d "${bundle}/Contents/PlugIns/imageformats" || mkdir -p "${bundle}/Contents/PlugIns/imageformats" || exit 1
cp -f ${QTDIR}/plugins/platforms/libqcocoa.dylib "${bundle}/Contents/PlugIns/platforms" || { echo libqcocoa.dylib not found in ${QTDIR}/plugins/platforms; exit 1; }
cp -f ${QTDIR}/plugins/imageformats/libqsvg.dylib "${bundle}/Contents/PlugIns/imageformats" || { echo libqsvg.dylib not found in ${QTDIR}/plugins/imageformats; exit 1; }
cp -f ${PGDIR}/lib/libpq.5.dylib "${bundle}/Contents/Frameworks" || { echo libpq.5.dylib not found in ${PGDIR}; exit 1; }
function CompleteSingleApp() {
local bundle=$1 tag=$(basename "$1") todo todo_old fw_relpath lib lib_bn nested_app na_relpath
echo "Completing app: ${bundle}"
pushd "${bundle}" > /dev/null
#We skip nested apps here - those are treated specially
todo=$(file `find ./ -perm +0111 ! -type d ! -path "*.app/*" ! -name "*.app"` | grep -E "Mach-O 64-bit" | awk -F ':| ' '{ORS=" "; print $1}')
echo "App: ${tag}: Found executables: ${todo}"
while test "${todo}" != ""; do
todo_old=${todo} ;
todo="" ;
for todo_obj in ${todo_old}; do
echo "App: ${tag}: Post-processing: ${todo_obj}"
#Figure out the relative path from todo_obj to Contents/Frameworks
fw_relpath=$(echo "${todo_obj}" |\
sed -n 's|^\(\.//*\)\(\([^/][^/]*/\)*\)[^/][^/]*$|\2|gp' | \
sed -n 's|[^/][^/]*/|../|gp' \
)"Contents/Frameworks"
fw_relpath_old=${fw_relpath}
fw_loc="Contents/Frameworks"
#Find all libraries $todo_obj depends on, but skip system libraries
for lib in $(
otool -L ${todo_obj} | \
grep "Qt\|dylib\|Frameworks\|PlugIns" | grep -v ":" | sed 's/(.*//' | egrep -v '(/usr/lib)|(/System)|@executable_path@' \
) $(otool -L ${todo_obj} | grep "Python" | grep -v ":" | sed 's/(.*//' \
); do
if echo ${lib} | grep "PlugIns\|libqcocoa" > /dev/null; then
lib_loc="Contents/PlugIns/platforms"
elif echo ${lib} | grep "PlugIns\|libqsvg" > /dev/null; then
lib_loc="Contents/PlugIns/imageformats"
elif echo ${lib} | grep "Qt" > /dev/null; then
qtfw_path="$(dirname ${lib} | sed 's|.*\(Qt.*framework\)|\1|')"
lib_loc="Contents/Frameworks/${qtfw_path}"
if [ "$(basename ${todo_obj})" = "${lib}" ]; then
lib_loc="$(dirname ${todo_obj})"
qtfw_path=$(echo ${lib_loc} | sed 's/Contents\/Frameworks\///')
fi
elif echo ${lib} | grep "Python" > /dev/null; then
pyfw_path="$(dirname ${lib} | sed 's|.*\(Python.*framework\)|\1|')"
lib_loc="Contents/Frameworks/${pyfw_path}"
if [ "$(basename ${todo_obj})" = "${lib}" ]; then
lib_loc="$(dirname ${todo_obj})"
pyfw_path=$(echo ${lib_loc} | sed 's/Contents\/Frameworks\///')
fi
else
lib_loc="Contents/Frameworks"
fi
lib_bn="$(basename "${lib}")" ;
if ! test -f "${lib_loc}/${lib_bn}"; then
target_file=""
target_path=""
echo "App: ${tag}: Adding symlink: ${lib_bn} (because of: ${todo_obj})"
# Copy the QT and Python framework
if echo ${lib} | grep Qt > /dev/null ; then
test -d ${lib_loc} || mkdir -p ${lib_loc}
echo Copying -R ${QTDIR}/lib/${qtfw_path}/${lib_bn} to ${lib_loc}/
cp ${QTDIR}/lib/${qtfw_path}/${lib_bn} ${lib_loc}/
elif echo ${lib} | grep Python > /dev/null ; then
test -d ${lib_loc} || mkdir -p ${lib_loc}
cp -R "${lib}" "${lib_loc}/${lib_bn}"
else
cp -R "${lib}" "${lib_loc}/${lib_bn}"
fi
if ! test -L "${lib_loc}/${lib_bn}"; then
chmod 755 "${lib_loc}/${lib_bn}"
else
target_file=$(readlink "${lib}")
target_path=$(dirname "${lib}")/${target_file}
echo "App: ${tag}: Adding symlink target: ${target_path}"
cp "${target_path}" "${lib_loc}/${target_file}"
chmod 755 "${lib_loc}/${target_file}"
fi
echo "Rewriting ID in ${lib_loc}/${lib_bn} to ${lib_bn}"
echo install_name_tool -id "${lib_bn}" "${lib_loc}/${lib_bn}"
install_name_tool \
-id "${lib_bn}" \
"${lib_loc}/${lib_bn}" || exit 1
todo="${todo} ./${lib_loc}/${lib_bn}"
fi
if echo ${lib} | grep Qt > /dev/null ; then
fw_relpath="${fw_relpath}/${qtfw_path}"
fi
if echo ${lib} | grep Python > /dev/null ; then
fw_relpath="${fw_relpath}/${pyfw_path}"
fi
chmod +w ${todo_obj}
echo "Rewriting library ${lib} to @loader_path/${fw_relpath}/${lib_bn} in ${todo_obj}"
echo install_name_tool -change "${lib}" "@loader_path/${fw_relpath}/${lib_bn}" "${todo_obj}"
install_name_tool -change \
"${lib}" \
"@loader_path/${fw_relpath}/${lib_bn}" \
"${todo_obj}" || exit 1
install_name_tool -change \
"${target_path}" \
"@loader_path/${fw_relpath}/${target_file}" \
"${todo_obj}" || exit 1
fw_relpath="${fw_relpath_old}"
done
done
done
# Fix the rpaths for psycopg module
find "${bundle}/Contents/Resources/venv/" -name _psycopg.so -print0 | xargs -0 install_name_tool -change libpq.5.dylib @loader_path/../../../../../../Frameworks/libpq.5.dylib
find "${bundle}/Contents/Resources/venv/" -name _psycopg.so -print0 | xargs -0 install_name_tool -change libssl.1.0.0.dylib @loader_path/../../../../../../Frameworks/libssl.1.0.0.dylib
find "${bundle}/Contents/Resources/venv/" -name _psycopg.so -print0 | xargs -0 install_name_tool -change libcrypto.1.0.0.dylib @loader_path/../../../../../../Frameworks/libcrypto.1.0.0.dylib
echo "App completed: ${bundle}"
popd > /dev/null
}
CompleteSingleApp "${bundle}"
-36
View File
@@ -1,36 +0,0 @@
#!/bin/sh
# move to the directory where we want to create the DMG
test -d ${DISTROOT} || mkdir ${DISTROOT}
cd ${DISTROOT}
DMG_SOURCES="./../mac-build/${APP_BUNDLE_NAME}"
DMG_LICENCE=./../pkg/mac/licence.rtf
DMG_VOLUME_NAME=${APP_NAME}
DMG_NAME=`echo ${DMG_VOLUME_NAME} | sed 's/ //g' | awk '{print tolower($0)}'`
DMG_IMAGE=${DMG_NAME}-${APP_LONG_VERSION}.dmg
HDIUTIL=/usr/bin/hdiutil
REZ="/usr/bin/Rez"
DMG_DIR=./${DMG_IMAGE}.src
if test -e "${DMG_DIR}"; then
echo "Directory ${DMG_DIR} already exists. Please delete it manually." >&2
exit 1
fi
echo "Cleaning up"
rm -f "${DMG_IMAGE}" || exit 1
mkdir "${DMG_DIR}" || exit 1
echo "Copying data into temporary directory"
for src in "${DMG_SOURCES}"; do
cp -R "${src}" "${DMG_DIR}" || exit 1
done
echo "Creating image"
${HDIUTIL} create -quiet -srcfolder "$DMG_DIR" -fs HFS+ -format UDZO -volname "${DMG_VOLUME_NAME}" -ov "${DMG_IMAGE}" || exit 1
rm -rf "${DMG_DIR}" || exit 1
echo "Attaching License to image"
python ./../pkg/mac/dmg-license.py "${DMG_IMAGE}" "${DMG_LICENCE}" -c bz2
-71
View File
@@ -1,71 +0,0 @@
#!/bin/sh
BUNDLE="$1"
if ! test -d "${BUNDLE}" ; then
echo "${BUNDLE} is no bundle!" >&2
exit 1
fi
# Get the config
source framework.conf
SCRIPT_DIR=`pwd`
echo Reorganising the framework structure
# Create "Current" and "Current/Resources" inside each of the framework dirs
MYDIR=`pwd`
find "${BUNDLE}/Contents/Frameworks"/*framework -type d -name "Versions" | while read -r framework_dir; do
cd "${framework_dir}"
# Create framework 'Current' soft link
VERSION_NUMBER=`ls -1`
ln -s ${VERSION_NUMBER} Current || { echo "link creation in framework-config.sh failed"; exit 1; }
# Create "Resources" subdirectory
if [ ! -d Current/Resources ]; then
mkdir Current/Resources
fi
cd "${MYDIR}"
done
# Stuff for Qt framework files only
find "${BUNDLE}/Contents/Frameworks" -type d -name "Qt*framework" | while read -r framework_dir; do
cd "${framework_dir}"
# Create soft link to the framework binary
ln -s Versions/Current/Qt* || { echo "link creation in framework-config.sh failed"; exit 1; }
# Create soft link to the framework Resources dir
ln -s Versions/Current/Resources || { echo "link creation in framework-config.sh failed"; exit 1; }
# Create the Info.plist files
MYNAME=`ls -1 Qt*`
if [ -f Resources/Info.plist ]; then
chmod +w Resources/Info.plist
fi
sed 's/__SHORT_VERSION__/${QT_SHORT_VERSION}/' "${SCRIPT_DIR}/Info.plist-template_Qt5" | sed 's/__FULL_VERSION__/${QT_FULL_VERSION}/' | sed "s/__FRAMEWORK_NAME__/${MYNAME}/" > "Resources/Info.plist" || { echo "sed replacement in framework-config.sh failed"; exit 1; }
cd "${MYDIR}"
done
# Same thing, but specific to the Python framework dir
find "${BUNDLE}/Contents/Frameworks" -type d -name "P*framework" | while read -r framework_dir; do
cd "${framework_dir}"
# Create soft link to the framework binary
ln -s Versions/Current/Py* || { echo "link creation in framework-config.sh failed"; exit 1; }
# Create soft link to the framework Resources dir
ln -s Versions/Current/Resources || { echo "link creation in framework-config.sh failed"; exit 1; }
# Create the Info.plist file
MYNAME=`ls -1 Py*`
sed 's/__SHORT_VERSION__/${PYTHON_SHORT_VERSION}/' "${SCRIPT_DIR}/Info.plist-template_Python" | sed 's/__FULL_VERSION__/${PYTHON_FULL_VERSION}/' | sed "s/__FRAMEWORK_NAME__/${MYNAME}/" > "Resources/Info.plist" || { echo "sed replacement in framework-config.sh failed"; exit 1; }
cd "${MYDIR}"
done
echo ${BUNDLE} framework config finished
+6 -6
View File
@@ -1,10 +1,10 @@
# copy this file to framework.conf, and edit the values below to reflect your environment
# (versions of Python/Qt used)
# Copy this file to framework.conf, and edit the values below to reflect your
# environment (versions of Python/Qt used)
PYTHON_SHORT_VERSION=2.7
PYTHON_FULL_VERSION=2.7.10
PYTHON_SHORT_VERSION=3.8
PYTHON_FULL_VERSION=3.8.2
QT_SHORT_VERSION=5.8
QT_FULL_VERSION=5.8.0
QT_SHORT_VERSION=5.14
QT_FULL_VERSION=5.14.2
+1 -1
View File
@@ -102,7 +102,7 @@ echo recursive-include pgadmin4 \* > pip-build/MANIFEST.in
# Run the build
echo Building wheel...
cd pip-build
python ../pkg/pip/setup_pip.py bdist_wheel --universal
python ../pkg/pip/setup_pip.py bdist_wheel
cd ../
# Get the build
+22 -40
View File
@@ -7,68 +7,51 @@
#
##########################################################################
import builtins
import os
import sys
from codecs import open
from importlib.machinery import SourceFileLoader
from setuptools import setup
from codecs import open
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# Load a source file
def load_source(name, path):
if not os.path.exists(path):
print("ERROR: Could not find %s" % path)
sys.exit(1)
return SourceFileLoader(name, path).load_module()
# Ensure the global server mode is set.
builtins.SERVER_MODE = None
"""This script helps to generate PIP packages"""
# Get the requirements list for the current version of Python
req_file = '../requirements.txt'
with open(req_file, 'r') as reqf:
if sys.version_info[0] >= 3:
required = reqf.read().splitlines()
else:
required = reqf.read().decode("utf-8").splitlines()
with open(req_file, 'r') as req_lines:
requires = req_lines.read().splitlines()
# Remove any requirements with environment specifiers. These
# must be explicitly listed in extras_require below.
for index, req in enumerate(required):
for index, req in enumerate(requires):
if ";" in req or req.startswith("#") or req == "":
required.remove(req)
requires.remove(req)
continue
# Ensure the Wheel will use psycopg2-binary, not the source distro
if 'psycopg2' in req:
required[index] = req.replace('psycopg2', 'psycopg2-binary')
requires[index] = req.replace('psycopg2', 'psycopg2-binary')
# Get the app version
if sys.version_info[:2] >= (3, 3):
from importlib.machinery import SourceFileLoader
def load_source(name, path):
if not os.path.exists(path):
print("ERROR: Could not find %s" % path)
sys.exit(1)
return SourceFileLoader(name, path).load_module()
else:
import imp
def load_source(name, path):
if not os.path.exists(path):
print("ERROR: Could not find %s" % path)
sys.exit(1)
return imp.load_source(name, path)
modl = load_source('APP_VERSION', '../web/config.py')
# Get the version
config = load_source('APP_VERSION', '../web/config.py')
setup(
name='pgadmin4',
version=modl.APP_VERSION,
version=config.APP_VERSION,
description='PostgreSQL Tools',
long_description='Administration and management tools for '
@@ -86,7 +69,6 @@ setup(
'Development Status :: 5 - Production/Stable',
# Supported programming languages
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
@@ -100,10 +82,10 @@ setup(
include_package_data=True,
install_requires=required,
install_requires=requires,
entry_points={
'console_scripts': ['pgadmin4=pgadmin4.pgAdmin4.__init__:main'],
'console_scripts': ['pgadmin4=pgadmin4.pgAdmin4:main'],
},
)
+64
View File
@@ -0,0 +1,64 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFtyz58BEACgKbtY59R0mxs8rWJNAn1BWNXwhuTvELNCV6gZkMRGFP14tMop
d9VcUx5UWiulT5wysji63xhkNljmE90jJdlxZwZ+XtnmLzIqp6i29EkAIUt1AoxM
w2ipMhfuwE6WA6VYxQihu5z2IDOR1PdDUHF5cX/GZgBon/2A33rG5IKTcaNZzL0O
c3rS5VzOzwnp1FHPlR7PY7BRDNe8q1MrQq14tlgMTaYziNg2t2YwjuhNV6G33qGE
h390aUnO/eMWIPJzKoi4mE5mhEbh4L/7sFlcRUC6Vs1xa5Ab+L5y2xoDe2grraKD
u+XpGJaDPLunlhDSTUsp0HsoLVU4ne/HNbCAm2b25tKFcFTUwDH4Ekge1/bQLCvx
kB63MMLa/FgsJ0XAr8zKEQFrc89qJU4JuvadL4hAIqZ1ywFlwTOBaNfZHbW2Pt5f
prktIL5d5jIHAdQrFPvLqhhjhM03de6O6dS5lDeP8dTdqzMcqBkwFMmjZMeRAcoJ
vs0jJNc0fYwL3h2JSWQnIhsvcSe6gk8GFVRbCCy9UplK1K/5TWw+y3mtfWwUCUSW
nBIuUTV+5iG21o3rdZgfEjXJtBAWW/hKoVwBTe5Ir9yIqaomG5ul0Sn2EgOravns
AWe2nk4l9cno5CPhGunEtiOD8YQJHskk7/NMtnPegB5j4tprXGS/cK/5hQARAQAB
tDxQYWNrYWdlIE1hbmFnZXIgKFBhY2thZ2UgU2lnbmluZyBLZXkpIDxwYWNrYWdl
c0BwZ2FkbWluLm9yZz6JAk4EEwEKADgWIQToaX4u73bALTpjMneIgbKoIQl28gUC
W3LPnwIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCIgbKoIQl28ukfD/4y
3gGysVSJU1964mpi/4NtSTruQ+fx8rN1vY/cctdQVr1ltuJsDRyPgGpXIh9zeK0/
bkCreCcuGezm2WOUFR6Kf54zMWWbIrAPpbib7rYi8n50jz7SkCfSyJZgqO2bAPBU
MP6Y09mdLaB4jib9Y6nDhFgm2V0rO64yX/bznVjBzNXFjCTgbPoABU0Guy4yHGUF
HkQ7Hdg1QLhupMWlphlMJbeSxZJx0T6ApNvr2Qg+uFykSXbXjP2e/tXGb9NeHveT
tw/hD2yMPzXJZ4uQbk8mJWDfD87fHY4ZUVqLJtKiS3omePJ5FWMPnLl0PLICkvmh
mhoxyKFGjB+62/PpYwclZLR8iB7wn9tIA/q6BqP/BBhgmzpuh7ZOAU/zUZ5D+tHu
Q9X0e29iFs4nxewmSM1uCq++l+gGMFRMn0FPH8nyQS/EcB/qXXRc0J3Ja7VVfH5B
djmVvqTeJmwY+xGdLZAh/WZ9raWd/qbRGNIcYOyhHnvp719EQxYSiiJbIQcRLDbc
IBiUG322ubSiR4+saYfx4ixrHvx8QYbtagien0kkXtoouhhIuLxq/EADRb979ZvQ
1hnlUkSGHRN6mDNyLztRqy/iibZrSgX+iKR9lQYI5MnhchihgoN7jyFUiGTV/VSG
6oH2KHiTgUQawli9OirnBB1oekf2+QZfZUvnM+b+SokCMwQQAQoAHRYhBODEzuuC
ax/aT7Ro4CSt+q9pjxUZBQJbcs/+AAoJECSt+q9pjxUZ4fAP/iQpwcrUZrPp3WI3
hi3wHAe+L6E6LiWlhMEMlqfy/2/xOpDEniwy6IEbMV7+H8WSbFYnTBM6EJAWPCMK
ZAfkduuB6xqHllEuPuFY9O13+fV5bJMrW/ej3MbX2yz+wfa6LLORRBB/e4R34suz
mlSzQzRttPHejmpNicn0S2kA07kqdl/2I3KcsWM1a5GeRZAukDSMLI6orZAGR+r4
xKpdEiEMHfoxYYxujmQR9+jqYYPsuViHc3LtIwaKMjTiWBx7wUDF+qIl7bNkT7P9
4VudNU9hhzCcYSAt4qiDykTojbSlXSx/ltqoTRhVQlk1kFk2g1O1zHyVpuAkolje
5ZmRGa/ZFQWuSOd01n1QqiRLrQDXHKDBh+sUOqaF4Hby/pwZwcsXGLEzSI9uC5He
WAn/yomDJInpyYwGmT9FyD9YSd9QjpM1y2/w2+KMj1KRq7GvmZUONYaWp1+A0eCL
yhdsZ+bqdS6DVnh0qKT/8ulWUKe+sxiRyAaKBF0QacuuRiRFAfgWbQbsrEQGcDqL
q7lmtmOKa0GrBQJAvTMUkxrpMG6SIe+HsJJ3/u+pmTWg77oiQqTByQPPJF0/EgMV
g/JzstHdI+FA7Q/4DKJZ5NrPBpUUQC0h+Iex426C7gBtnGXQHYB2Nx6xCtwmpPZv
w5THrRb07Y59nZEZLEdcL8bbH/CZuQINBFtyz58BEACt0Hcb8t24ZXsGcOlVnElo
cMMo17IdyDvs1j2jJxrNTT6jkxlgwG+ojStsRvllRrG85Wq/FNI6LuBY3Ux+Ymda
Nm+p8CJiEDE/Gql4GPSNZ7fCiiopRyyFXg61VM72lWokAT9o9GaSU0/sM5WDeXvM
A5QIlAg6+jQ7+R0MMLHeH0GTMnF58KAFmE7T72+H1zPtvH3qeQlOt+PBMJVNhjiO
2MwU7NlUIKVz4Vn1JmxA1kCWEIxZyFS82XXKc9BXgPqwnk27lqBxdZzDWFki8SBn
DdvwTT/s0chtwekWN4t2RofK0w33TF7+MSQLxpWLr8igrQQvBq6LBfMqm8tQWHL2
VDORDg5kKIpZv4pNxxIFmu1VX+W01Oj2GV6AOJgX6jadMiRlHptkz7D/dmnqsCyf
DRCmLcwB3y2/behbV1+iW2bViUaFoQIt/XXm2Jo1YtskxZ7LDngDin88pU6jId1N
dxjP2rKUjm/dyH5jMn1engv71w16TH+GVr42ho+yOwOTYo8qKDAvQgI8I8e+MlkM
LRLpgmFiECmWCovJOQ2JHizqFOmr+eSbeg7o5VpWA+cb0sCdbGUX8Kv6i8zP/ayh
VnWg1oU5Q0HTgH9gQ0rzkR+Re2O5xSKuNYnqVOJv4eRzt1NPFgZZOw+PFMJlvEz4
ujGwA/OsdJNLQK/HEK75GwARAQABiQI2BBgBCgAgFiEE6Gl+Lu92wC06YzJ3iIGy
qCEJdvIFAltyz58CGwwACgkQiIGyqCEJdvKPUg//f2YJGHX9FaNkCpoEk51QW5sv
pqITO24Ig65mEVVyx1GPOR9BQnCJoXZrnhEv2d/BpijFE/cR/fHv9bmqc434waeZ
PyDyflWTn6+MQYMJJfszKdJFaaY4qPeaCcoh7GC2qw4I5MINfNVTcinOU52XZzt6
F+ENm4h8u6vbS+55sKXjRRxNMHbBlNMr0yylukdGrs3PTGEYtXEPBhms4Plz5uHj
wkvf+rti84z2qqdX6y0YWxtRBy0cGeo15NYA8kHJLIQeUYbkV20PC7Uooj29DpIs
RxDv7F2qZ3KIse8oiJTIubdM+O7zNhzMo+XSUY2HM6aWDLCjV5SuJVJUsPxA3aEK
ijn/PjmGkr4DKhiant0nIB/pzyKelNQJHO5fgCFuV72R9GIR7yBRG2AU5OwgHQdy
5F0/4/6LtNVWZMKy2lEYuyW8fm0rbC7G5Qbz0KhYZWxp3F20rO6679ViMuNQTwQf
HI9akdtFqFEFPuoHyT3VAMxzeUAcMXwBaPcHw1EOlX1kibaM5dbDVOfKEr6JNj4V
N00CeuM++rHJSTeM/gcxO+BWpzaNFF9MMrCBL74wiY+WJ7rogRf5Du7H2e0+w/XO
puIx3rGSO9VhVrVcoTHimJPuWH7j56wybLS/TCh6HI8soMjYLzxWbqvSyV0b4xfb
czb/7fY4Fah80eE59/M=
=E6/L
-----END PGP PUBLIC KEY BLOCK-----
+98 -7
View File
@@ -1,6 +1,12 @@
This directory contains the build runner script for creating .RPM packages for
Redhat distributions.
Supported platforms
===================
Fedora 30, 31 & 32
RHEL/CentOS 7 & 8
Build configuration
===================
@@ -39,13 +45,98 @@ pgadmin4-python3-mod_wsgi-4.7.1-2.el7.<arch>.rpm
The Python 3 build of mod_wsgi for the Apache HTTPD server. Only built
on RHEL/CentOS 7.
Supported platforms
===================
Signing Packages
================
Fedora 30 & 31
RHEL/CentOS 7 & 8
It is good practice to sign RPMs to prove their provenance. The build scripts
included in this directory do NOT do that; doing so is done using a Jenkins
task in the pgAdmin buildfarm.
Warning
=======
If you want to sign your own RPMs, you'll first need to ensure that the
gnupg2 and rpmsign tools are available on your system.
These scripts are experimental - use at your own risk!
Then, create a .rpmmacros file in the home directory of the user account that
will be doing the signing. On Fedora 30 and later, and RHEL/CentOS 8 and later,
that should contain the following contents (without the start/end markers).
Replace <your signing key> with the email address in your key:
---------
%_signature gpg
%_gpg_path ~/.gnupg
%_gpg_name <your signing key>
%_gpgbin /usr/bin/gpg2
%__gpg_sign_cmd %{__gpg} gpg --force-v3-sigs --batch --verbose --no-armor --no-secmem-warning -u "%{_gpg_name}" -sbo %{__signature_filename
} --digest-algo sha256 %{__plaintext_filename}
---------
On RHEL/CentOS 7, the .rpmmacros file should look like this:
---------
%_signature gpg
%_gpg_path ~/.gnupg
%_gpg_name Package Manager
%_gpgbin /usr/bin/gpg2
%__gpg_sign_cmd %{__gpg} gpg --force-v3-sigs --batch --verbose --no-armor --passphrase-fd 3 --no-secmem-warning -u "%{_gpg_name}" -sbo %{__
signature_filename} --digest-algo sha256 %{__plaintext_filename}
---------
Note that these configurations are designed for automated signing in a CI/CD
system. You may need to adjust them to handle passphrases on keys in your own
environment.
You also need to import your signing private key into the gnupg2 keystore, for
example:
gpg --import signing_key.priv
Once everything is setup, RPMs can be signed easily; for example:
rpmsign --addsign dist/*.rpm
Building a repo
===============
A Yum repo can be created by building RPMs for the required platforms, moving
them into the required directory structure, and then running the createrepo tool
over that directory. The pgAdmin repos use the following structure:
<root>
redhat/
rhel-7-x86_64/
pgadmin4-4.21-1.el7.noarch.rpm
pgadmin4-desktop-4.21-1.el7.x86_64.rpm
pgadmin4-python3-mod_wsgi-4.7.1-2.el7.x86_64.rpm
pgadmin4-server-4.21-1.el7.x86_64.rpm
pgadmin4-web-4.21-1.el7.noarch.rpm
rhel-8-x86_64/
<...>
fedora/
<...>
pgadmin4-fedora-repo-1-1.noarch.rpm
pgadmin4-redhat-repo-1-1.noarch.rpm
README
Note that only the first branches are shown above; other branches (e.g. for
Fedora and RHEL 8 follow the structure shown for RHEL 7.
Technically there are multiple different repos, one for each platform and
architecture. The metadata can be created for each as follows:
/usr/bin/createrepo <root>/redhat/rhel-7-x86_64
/usr/bin/createrepo <root>/redhat/rhel-8-x86_64
...
Repository RPMs
===============
A script is provided for the creation of repo RPMs. It will create RPMs that
install the required Yum configuration file and the public signing key for
pgAdmin (you may want to replace the contents of PGADMIN_PKG_KEY with your own
public key):
./repo-rpms.sh
Set the PGADMIN_REPO_DIR environment variable to define the repository root
from the client's perspective. Given the example above, you might do:
PGADMIN_REPO_DIR=https://yum.company.com/repos/<root> ./repo-rpms.sh
+112
View File
@@ -0,0 +1,112 @@
#!/bin/bash
# Set the repo RPM version and build
REPO_RPM_VERSION=1
REPO_RPM_BUILD=1
# Set the repo base directory
if [ "x${PGADMIN_REPO_DIR}" == "x" ]; then
echo "PGADMIN_REPO_DIR not set. Setting it to the default: https://ftp.postgresql.org/pub/pgadmin/pgadmin4/repos/yum"
export PGADMIN_REPO_DIR=https://ftp.postgresql.org/pub/pgadmin/pgadmin4/repos/yum
fi
# Exit when any command fails
set -e
# Debugging shizz
trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
trap 'if [ $? -ne 0 ]; then echo "\"${last_command}\" command filed with exit code $?."; fi' EXIT
OS_VERSION=$(cat /etc/os-release | grep "^VERSION_ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
OS_NAME=$(cat /etc/os-release | grep "^ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
OS_ARCH=$(arch)
# Common Linux build functions
source pkg/linux/build-functions.sh
# Are we installing a package key?
INCLUDE_KEY=0
if [ -f "pkg/redhat/PGADMIN_PKG_KEY" ]; then
INCLUDE_KEY=1
echo "Building repo RPMs including a package signing key..."
else
echo "pkg/redhat/PGADMIN_PKG_KEY not found."
echo "Building repo RPMs WITHOUT a package signing key..."
sleep 5
fi
# Create the Redhat packaging stuffs for the repo
_create_repo_rpm() {
DISTRO=$1
if [ ${DISTRO} == "redhat" ]; then
PLATFORM="rhel"
else
PLATFORM=${DISTRO}
fi
echo "Creating the repo package for ${DISTRO}..."
test -d ${BUILDROOT}/${DISTRO}-repo/etc/yum.repos.d || mkdir -p ${BUILDROOT}/${DISTRO}-repo/etc/yum.repos.d
cat << EOF > "${BUILDROOT}/${DISTRO}-repo/etc/yum.repos.d/pgadmin4.repo"
[pgAdmin4]
name=pgadmin4
baseurl=${PGADMIN_REPO_DIR}/${DISTRO}/${PLATFORM}-\$RELEASEVER-\$BASEARCH
enabled=1
EOF
if [ ${INCLUDE_KEY} -eq 1 ]; then
echo gpgcheck=1 >> "${BUILDROOT}/${DISTRO}-repo/etc/yum.repos.d/pgadmin4.repo"
else
echo gpgcheck=0 >> "${BUILDROOT}/${DISTRO}-repo/etc/yum.repos.d/pgadmin4.repo"
fi
echo "Creating the spec file for ${DISTRO}..."
cat << EOF > "${BUILDROOT}/${DISTRO}-repo.spec"
%global __requires_exclude_from ^/.*$
%global __provides_exclude_from ^/.*$
Name: ${APP_NAME}-${DISTRO}-repo
Version: ${REPO_RPM_VERSION}
Release: ${REPO_RPM_BUILD}
BuildArch: noarch
Summary: Repository configuration for the pgAdmin ${DISTRO^} repositories.
License: PostgreSQL
URL: https://www.pgadmin.org/
%description
The yum repository configuration for ${DISTRO^} platforms.
%build
%install
cp -rfa %{pga_build_root}/${DISTRO}-repo/* \${RPM_BUILD_ROOT}
%files
/etc/yum.repos.d/pgadmin4.repo
EOF
if [ ${INCLUDE_KEY} -eq 1 ]; then
cat << EOF >> ${BUILDROOT}/${DISTRO}-repo.spec
/etc/pki/rpm-gpg/PGADMIN_PKG_KEY
%post
rpm --import /etc/pki/rpm-gpg/PGADMIN_PKG_KEY
EOF
test -d ${BUILDROOT}/${DISTRO}-repo/etc/pki/rpm-gpg || mkdir -p ${BUILDROOT}/${DISTRO}-repo/etc/pki/rpm-gpg
cp pkg/redhat/PGADMIN_PKG_KEY ${BUILDROOT}/${DISTRO}-repo/etc/pki/rpm-gpg/
fi
# Build the package
echo "Building the repo RPM for ${DISTRO}..."
rpmbuild --define "pga_build_root ${BUILDROOT}" -bb "${BUILDROOT}/${DISTRO}-repo.spec"
}
_setup_env $0 "redhat"
_create_repo_rpm redhat
_create_repo_rpm fedora
#
# Get the results!
#
test -d "${DISTROOT}/" || mkdir -p "${DISTROOT}/"
cp ${HOME}/rpmbuild/RPMS/noarch/${APP_NAME}-*-repo-${REPO_RPM_VERSION}-${REPO_RPM_BUILD}.noarch.rpm "${DISTROOT}/"
+3 -3
View File
@@ -4,7 +4,7 @@
To generate a pgAdmin 4 installer for Windows bit, the following packages must be installed:
1. Python installation
- Python 2.7 or 3.4+ or above from https://www.python.org/
- Python 3.4+ or above from https://www.python.org/
2. QT installation
- Qt 4.6 through 5.5 from http://www.qt.io/
@@ -21,8 +21,8 @@ Building: Depending upon the archicture of the OS(x86|amd64) set then environmen
1. Set the PYTHON environment variable to the Python root installation directory, e.g. for x86
SET "PYTHON_HOME=C:\Python27"
SET "PYTHON_DLL=C:\Windows\System32\python27.dll"
SET "PYTHON_HOME=C:\Python38"
SET "PYTHON_DLL=C:\Windows\System32\python38.dll"
2. Set the QTDIR environment variable to the QT root installation directory, e.g. for x86
+46 -38
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>975</width>
<height>398</height>
<width>800</width>
<height>415</height>
</rect>
</property>
<property name="sizePolicy">
@@ -18,8 +18,8 @@
</property>
<property name="minimumSize">
<size>
<width>975</width>
<height>300</height>
<width>800</width>
<height>415</height>
</size>
</property>
<property name="windowTitle">
@@ -81,7 +81,7 @@
</property>
<property name="minimumSize">
<size>
<width>150</width>
<width>250</width>
<height>0</height>
</size>
</property>
@@ -96,22 +96,6 @@
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="browserCommandLineEdit">
<property name="placeholderText">
@@ -132,7 +116,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
@@ -159,7 +143,7 @@
</property>
<property name="minimumSize">
<size>
<width>150</width>
<width>250</width>
<height>0</height>
</size>
</property>
@@ -261,7 +245,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
@@ -280,6 +264,12 @@
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_9">
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Open a Browser Window/Tab at Startup?</string>
</property>
@@ -365,8 +355,8 @@
</property>
<property name="minimumSize">
<size>
<width>450</width>
<height>28</height>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
@@ -401,10 +391,16 @@
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="pythonPathLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>20</height>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="layoutDirection">
@@ -427,12 +423,12 @@
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
@@ -458,8 +454,8 @@
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>20</height>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
@@ -499,6 +495,18 @@
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QLabel" name="applicationPathLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Application Path</string>
</property>
@@ -513,12 +521,12 @@
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
@@ -544,8 +552,8 @@
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>20</height>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
+2 -2
View File
@@ -8,9 +8,9 @@
<key>CFBundleName</key>
<string>pgAdmin 4</string>
<key>CFBundleShortVersionString</key>
<string>4.21.0</string>
<string>4.22.0</string>
<key>CFBundleVersion</key>
<string>4.21.0</string>
<string>4.22.0</string>
<key>LSMinimumSystemVersion</key>
<string>10.10</string>
<key>NSHumanReadableCopyright</key>
+25 -11
View File
@@ -9,6 +9,7 @@
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin4.h"
#include "LogWindow.h"
#include "ui_LogWindow.h"
@@ -16,10 +17,10 @@
#include <stdio.h>
LogWindow::LogWindow(QWidget *parent, QString logFile) :
LogWindow::LogWindow(QWidget *parent, QString serverLogFile) :
QDialog(parent),
ui(new Ui::LogWindow),
m_logFile(logFile)
m_serverLogFile(serverLogFile)
{
ui->setupUi(this);
}
@@ -31,14 +32,27 @@ LogWindow::~LogWindow()
}
void LogWindow::LoadLog()
{
int startupLines, serverLines;
ui->lblStatus->setText(tr("Loading logfiles..."));
startupLines = this->readLog(QDir::homePath() + (QString("/.%1.startup.log").arg(PGA_APP_NAME)).remove(" "), ui->textStartupLog);
serverLines = this->readLog(m_serverLogFile, ui->textServerLog);
ui->lblStatus->setText(QString(tr("Loaded startup log (%1 lines) and server log (%2 lines).")).arg(startupLines).arg(serverLines));
}
void LogWindow::reload()
{
this->ReadLog();
this->LoadLog();
}
// Read the logfile
void LogWindow::ReadLog()
int LogWindow::readLog(QString logFile, QPlainTextEdit *logWidget)
{
FILE *log;
char *buffer;
@@ -47,20 +61,19 @@ void LogWindow::ReadLog()
// Look busy!
QApplication::setOverrideCursor(Qt::WaitCursor);
ui->lblStatus->setText(tr("Loading logfile..."));
this->setDisabled(true);
QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
ui->textLog->clear();
logWidget->clear();
// Attempt to open the file
log = fopen(m_logFile.toUtf8().data(), "r");
log = fopen(logFile.toUtf8().data(), "r");
if (log == Q_NULLPTR)
{
ui->textLog->setPlainText(QString(tr("The log file (%1) could not be opened.")).arg(m_logFile));
logWidget->setPlainText(QString(tr("The log file (%1) could not be opened.")).arg(m_serverLogFile));
this->setDisabled(false);
QApplication::restoreOverrideCursor();
return;
return 0;
}
// Get the file size, and read the data
@@ -80,10 +93,11 @@ void LogWindow::ReadLog()
buffer[i] = 0;
fclose(log);
ui->textLog->setPlainText(buffer);
logWidget->setPlainText(buffer);
// And... relax
ui->lblStatus->setText(QString(tr("Loaded logfile (%1 lines).")).arg(lines));
this->setDisabled(false);
QApplication::restoreOverrideCursor();
return lines;
}
+7 -3
View File
@@ -13,6 +13,7 @@
#define LOGWINDOW_H
#include <QDialog>
#include <QPlainTextEdit>
namespace Ui {
class LogWindow;
@@ -23,10 +24,10 @@ class LogWindow : public QDialog
Q_OBJECT
public:
explicit LogWindow(QWidget *parent = Q_NULLPTR, QString logFile = "");
explicit LogWindow(QWidget *parent = Q_NULLPTR, QString serverLogFile = "");
~LogWindow();
void ReadLog();
void LoadLog();
private slots:
void reload();
@@ -34,7 +35,10 @@ private slots:
private:
Ui::LogWindow *ui;
QString m_logFile;
QString m_startupLogFile;
QString m_serverLogFile;
int readLog(QString logFile, QPlainTextEdit *logWidget);
};
#endif // LOGWINDOW_H
+33 -1
View File
@@ -15,7 +15,39 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="textLog">
<widget class="QLabel" name="lblStartupLog">
<property name="text">
<string>Startup Log:</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="textStartupLog">
<property name="font">
<font>
<family>Courier</family>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="plainText">
<string notr="true"/>
</property>
<property name="centerOnScroll">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblServerLog">
<property name="text">
<string>Server Log:</string>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="textServerLog">
<property name="font">
<font>
<family>Courier</family>
+1 -1
View File
@@ -134,7 +134,7 @@ void MenuActions::onLog()
QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
m_logWindow->ReadLog();
m_logWindow->LoadLog();
}
-39
View File
@@ -72,15 +72,11 @@ Server::Server(quint16 port, QString key, QString logFileName)
PGA_APP_NAME_UTF8 = PGA_APP_NAME.toUtf8();
// Python3 requires conversion of char * to wchar_t *, so...
#ifdef PYTHON2
Py_SetProgramName(PGA_APP_NAME_UTF8.data());
#else
char *appName = PGA_APP_NAME_UTF8.data();
const size_t cSize = strlen(appName)+1;
m_wcAppName = new wchar_t[cSize];
mbstowcs (m_wcAppName, appName, cSize);
Py_SetProgramName(m_wcAppName);
#endif
// Setup the search path
QSettings settings;
@@ -183,16 +179,12 @@ Server::Server(quint16 port, QString key, QString logFileName)
if (!pythonHome.isEmpty())
{
pythonHome_utf8 = pythonHome.toUtf8();
#ifdef PYTHON2
Py_SetPythonHome(pythonHome_utf8.data());
#else
char *python_home = pythonHome_utf8.data();
const size_t cSize = strlen(python_home) + 1;
m_wcPythonHome = new wchar_t[cSize];
mbstowcs (m_wcPythonHome, python_home, cSize);
Py_SetPythonHome(m_wcPythonHome);
#endif
}
Logger::GetLogger()->Log("Initializing Python...");
@@ -207,15 +199,7 @@ Server::Server(quint16 port, QString key, QString logFileName)
Logger::GetLogger()->Log("Adding new additional path elements");
for (i = path_list.size() - 1; i >= 0 ; --i)
{
#ifdef PYTHON2
PyList_Append(sysPath, PyString_FromString(path_list.at(i).toUtf8().data()));
#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()));
#endif
#endif
}
}
else
@@ -227,9 +211,6 @@ Server::Server(quint16 port, QString key, QString logFileName)
if (sys != Q_NULLPTR)
{
PyObject *err = Q_NULLPTR;
#ifdef PYTHON2
err = PyFile_FromString(m_logFileName.toUtf8().data(), (char *)"w");
#else
FILE *log = Q_NULLPTR;
#if defined(Q_OS_WIN)
@@ -256,7 +237,6 @@ Server::Server(quint16 port, QString key, QString logFileName)
delete wcLogFileName;
wcLogFileName = NULL;
}
#endif
#endif
QFile(m_logFileName).setPermissions(QFile::ReadOwner|QFile::WriteOwner);
if (err != Q_NULLPTR)
@@ -347,25 +327,7 @@ void Server::run()
// Run the app!
QByteArray m_appfile_utf8 = m_appfile.toUtf8();
#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_utf8.data() };
PySys_SetArgv(1, n_argv);
Logger::GetLogger()->Log("PyRun_SimpleFile launching application server...");
PyObject* PyFileObject = PyFile_FromString(m_appfile_utf8.data(), (char *)"r");
int ret = PyRun_SimpleFile(PyFile_AsFile(PyFileObject), m_appfile_utf8.data());
if (ret != 0)
{
Logger::GetLogger()->Log("Failed to launch the application server, server thread exiting.");
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,
@@ -385,7 +347,6 @@ void Server::run()
Logger::GetLogger()->Log("Failed to launch the application server, server thread exiting.");
setError(tr("Failed to launch the application server, server thread exiting."));
}
#endif
fclose(cp);
}
+5
View File
@@ -10,13 +10,18 @@
//////////////////////////////////////////////////////////////////////////
#import <Cocoa/Cocoa.h>
#import <Availability.h>
// Detect if we're running in Dark mode
bool IsDarkMode() {
#ifdef __MAC_10_14
if (@available(macOS 10.14, *)) {
NSString *interfaceStyle = [NSUserDefaults.standardUserDefaults valueForKey:@"AppleInterfaceStyle"];
return [interfaceStyle isEqualToString:@"Dark"];
} else {
return NO;
}
#else
return NO;
#endif
}
+89 -79
View File
@@ -1,15 +1,19 @@
VERSION = 4.21.0.0
VERSION = 4.22.0.0
QMAKE_TARGET_COMPANY = "The pgAdmin Development Team"
QMAKE_TARGET_PRODUCT = "pgAdmin 4"
QMAKE_TARGET_DESCRIPTION = "pgAdmin 4 Desktop Runtime"
QMAKE_TARGET_COPYRIGHT = "Copyright (C) 2013 - 2020, The pgAdmin Development Team"
message(==================================)
message(Configuring the pgAdmin 4 runtime.)
message(==================================)
# Configure QT modules for the appropriate version of QT
greaterThan(QT_MAJOR_VERSION, 4) {
message(Building for QT5+...)
message(Qt version: 5)
QT += network widgets
} else {
message(Building for QT4...)
message(Qt version: 4)
QT += network
DEFINES += Q_NULLPTR=NULL
}
@@ -22,98 +26,104 @@ QMAKE_CFLAGS += $$(PGADMIN_CFLAGS)
QMAKE_CXXFLAGS += $$(PGADMIN_CXXFLAGS)
QMAKE_LFLAGS += $$(PGADMIN_LDFLAGS)
# Figure out where/what Python looks like and that it's suitable
PYTHON_DIR = $$(PGADMIN_PYTHON_DIR)
equals(PYTHON_DIR, "") {
error(The PGADMIN_PYTHON_DIR environment variable is not set. Please set it to a directory path under which Python 3.4 or later has been installed and try again.)
}
win32 {
message(Building for Windows...)
# Read the PYTHON_HOME and PYTHON_VERSION system environment variables.
PY_HOME = $$(PYTHON_HOME)
PY_VERSION = $$(PYTHON_VERSION)
isEmpty(PY_HOME) {
error(Please define the PYTHON_HOME variable in the system environment.)
message(Platform: Windows)
PYTHON_EXE = $${PYTHON_DIR}\python.exe
} else {
macx {
message(Platform: macOS)
} else {
message(Platform: Linux)
}
else {
isEmpty(PY_VERSION) {
error(Please define the PYTHON_VERSION variable in the system environment.)
}
else {
INCLUDEPATH = $$PY_HOME\include
LIBS += -L"$$PY_HOME\libs" -lpython$$PY_VERSION
PYTHON_EXE = $${PYTHON_DIR}/bin/python3
}
# Set the PYTHON2 macro if appropriate
PY2_VERSION = $$find(PY_VERSION, "^2")
count( PY2_VERSION, 1) {
message(Python version 2.x detected.)
DEFINES += PYTHON2
}
}
}
!exists($$PYTHON_EXE) {
error(The Python executable ($$PYTHON_EXE) could not be found. Please ensure the PGADMIN_PYTHON_DIR environment variable is correctly set.)
}
message(Python executable: $$PYTHON_EXE)
PYTHON_VERSION = $$system($$PYTHON_EXE -c \"import sys; print(\'%s.%s\' % (sys.version_info[0], sys.version_info[1]))\")
PYTHON_SHORT_VERSION = $$system($$PYTHON_EXE -c \"import sys; print(\'%s%s\' % (sys.version_info[0], sys.version_info[1]))\")
PYTHON_MAJOR_VERSION = $$system($$PYTHON_EXE -c \"import sys; print(sys.version_info[0])\")
message(Python version: $$PYTHON_VERSION ($$PYTHON_SHORT_VERSION))
lessThan(PYTHON_SHORT_VERSION, 34) {
error(Python 3.4 or later is required to build pgAdmin.)
}
# Configure for the platform
win32 {
INCLUDEPATH = $${PYTHON_DIR}\include
message(Include path: $$INCLUDEPATH)
LIBS += -L"$${PYTHON_DIR}\libs" -lpython$${PYTHON_SHORT_VERSION}
message(LIBS: $$LIBS)
}
else {
message(Building for Linux/Mac...)
# Find and configure Python
# Environment setting
PYTHON_CONFIG = $$(PYTHON_CONFIG)
# Python 2?
isEmpty(PYTHON_CONFIG) {
PYTHON_CONFIG = $$system(which python-config)
# Find the best matching python-config (there may be more than one)
exists($PYTHON_DIR/bin/python$${PYTHON_VERSION}-config) {
PYTHON_CONFIG = $$PYTHON_DIR/bin/python$${PYTHON_VERSION}-config
} else: exists($${PYTHON_DIR}/bin/python$${PYTHON_MAJOR_VERSION}-config) {
PYTHON_CONFIG = $${PYTHON_DIR}/bin/python$${PYTHON_MAJOR_VERSION}-config
} else: exists($${PYTHON_DIR}/bin/python-config) {
PYTHON_CONFIG = $${PYTHON_DIR}/bin/python-config
} else {
error(No suitable python-config could be found in $${PYTHON_DIR}/bin.)
}
message(Python config: $$PYTHON_CONFIG)
# Maybe Python 3?
isEmpty(PYTHON_CONFIG) {
PYTHON_CONFIG = $$system(which python3-config)
}
# Argh!
isEmpty(PYTHON_CONFIG) {
error(The python-config executable could not be found. Ensure Python is installed and in the system path.)
}
message(Using $$PYTHON_CONFIG)
PYTHON_EMBED = $$system($$PYTHON_CONFIG --help 2>&1 | grep -o \'\\-\\-embed\')
QMAKE_CXXFLAGS += $$system($$PYTHON_CONFIG --includes)
QMAKE_LFLAGS += $$system($$PYTHON_CONFIG --ldflags)
LIBS += $$system($$PYTHON_CONFIG --libs)
message(CXXFLAGS: $$QMAKE_CXXFLAGS)
contains( LIBS, -lpython2.* ) {
DEFINES += PYTHON2
message(Python2 detected.)
} else {
message(Python3 detected.)
}
QMAKE_LFLAGS += $$system($$PYTHON_CONFIG --ldflags)
message(LDFLAGS: $$QMAKE_LFLAGS)
LIBS += $$system($$PYTHON_CONFIG --libs $$PYTHON_EMBED)
message(LIBS: $$LIBS)
}
# Source code
HEADERS = Server.h \
pgAdmin4.h \
ConfigWindow.h \
TrayIcon.h \
LogWindow.h \
MenuActions.h \
FloatingWindow.h \
Logger.h
SOURCES = pgAdmin4.cpp \
Server.cpp \
ConfigWindow.cpp \
TrayIcon.cpp \
LogWindow.cpp \
MenuActions.cpp \
FloatingWindow.cpp \
Logger.cpp
HEADERS = Server.h \
pgAdmin4.h \
ConfigWindow.h \
TrayIcon.h \
LogWindow.h \
MenuActions.h \
FloatingWindow.h \
Logger.h
FORMS = ConfigWindow.ui \
LogWindow.ui \
FloatingWindow.ui
ICON = pgAdmin4.icns
QMAKE_INFO_PLIST = Info.plist
SOURCES = pgAdmin4.cpp \
Server.cpp \
ConfigWindow.cpp \
TrayIcon.cpp \
LogWindow.cpp \
MenuActions.cpp \
FloatingWindow.cpp \
Logger.cpp
RESOURCES += pgadmin4.qrc \
breeze.qrc
FORMS = ConfigWindow.ui \
LogWindow.ui \
FloatingWindow.ui
ICON = pgAdmin4.icns
QMAKE_INFO_PLIST = Info.plist
RESOURCES += pgadmin4.qrc \
breeze.qrc
macx {
HEADERS += macos.h
OBJECTIVE_SOURCES = macos.mm
HEADERS += macos.h
OBJECTIVE_SOURCES = macos.mm
}
+1 -4
View File
@@ -52,10 +52,7 @@ def get_python_deps():
"/../requirements.txt")
with open(req_file, 'r') as req_file_p:
if sys.version_info[0] >= 3:
required = req_file_p.read().splitlines()
else:
required = req_file_p.read().decode("utf-8").splitlines()
required = req_file_p.read().splitlines()
# Get the package info from the requirements file
requirements = pkg_resources.parse_requirements(required)
+280
View File
@@ -0,0 +1,280 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
# #########################################################################
# Updates browser images(selenoid-docker) depending on arguments passed while
# running this script.
# e.g. --chrome /usr/bin/google-chrome --firefox /usr/bin/firefox
# Access details about switches using help
# e.g. --help
import argparse
import os
import subprocess
import sys
import traceback
import requests
import json
def read_command_line():
"""Read the command line arguments.
Returns:
ArgumentParser: The parsed arguments object
"""
parser = argparse.ArgumentParser(
description='Get latest browser images(chrome & firefox) for selenoid.'
'e.g. - --chrome /usr/bin/google-chrome --firefox '
'/usr/bin/firefox')
parser.add_argument("--chrome", metavar="CHROME",
help="the Chrome executable path")
parser.add_argument("--firefox", metavar="FIREFOX",
help="the firefox executable path")
args_val = parser.parse_args()
return args_val
def get_browser_version(browser_name, executable_path):
"""
Function returns browser version for specified browser using executable
path passed in arguments.
:param browser_name:
:param executable_path: e.g. /usr/bin/firefox
:return: browser version
"""
# On Linux/Mac we run the browser executable with the --version flag,
# then parse the output.
browser_version_val = None
try:
result = subprocess.Popen([executable_path, '--version'],
stdout=subprocess.PIPE)
except FileNotFoundError:
print('The specified browser executable could not be found.')
sys.exit(1)
version_str = result.stdout.read().decode("utf-8")
if browser_name.lower() == "chrome":
# Check for 'Chrom' not 'Chrome' in case the user is using Chromium.
if "Chrom" not in version_str:
print('The specified Chrome executable output an unexpected '
'version string: {}.'.format(version_str))
sys.exit(1)
# On some linux distro `chrome--version` gives output like
# 'Google Chrome 80.0.3987.132 unknown\n'
# so we need to check and remove the unknown string from the version
if version_str.endswith("unknown\n"):
version_str = version_str.strip("unknown\n").strip()
chrome_version = '.'.join(version_str.split()[-1].split('.')[:-2])
# Make sure browser version has only 1 decimal point
if chrome_version.count('.') != 1:
print('The specified Chrome executable output an unexpected '
'version string: {}.'.format(version_str))
sys.exit(1)
browser_version_val = chrome_version
elif browser_name.lower() == "firefox":
if "Firefox" not in version_str:
print('The specified Firefox executable output an unexpected '
'version string: {}.'.format(version_str))
sys.exit(1)
# Some time firefox --version gives output like
# 'Running without a11y support!
# Mozilla Firefox 68.7.0esr'
# Other output - [root@localhost local]# /usr/bin/firefox --version
# Mozilla Firefox 75.0
if 'esr' in version_str:
firefox_version = '.'.join(
version_str.split('esr')[0].split()[-1].split('.')[:-1])
else:
firefox_version = '.'.join(
version_str.split()[-1].split('.')[:-1])
if firefox_version.count('.') == 0:
firefox_version = firefox_version + '.0'
# Make sure browser version has only 1 decimal point
if firefox_version.count('.') != 1:
print('The specified Firefox executable output an unexpected '
'version string: {}.'.format(version_str))
sys.exit(1)
browser_version_val = firefox_version
else:
print("{0} is not recognised ".format(browser_name))
sys.exit(1)
return browser_version_val
def check_and_download_vnc_browser_image(browser_name, browser_version):
"""
Function checks presence for vnc images for passed browser
at docker.io/selenoid/ registry
:param browser_name:
:param browser_version:
:return:true if browser image is available & downloaded else false
"""
res = requests.get(
'https://registry.hub.docker.com/v2/repositories/selenoid/vnc_' +
browser_name + '/tags/')
res = res.json()
version_tag = []
if len(res['results']) > 0:
for result in res['results']:
if 'name' in result:
version_tag.append(result['name'])
vnc_image_available = False
image_name = 'vnc_' + browser_name + ':' + browser_version
for idx, tag in enumerate(version_tag):
if browser_version == tag:
command = 'docker pull selenoid/vnc_' + browser_name + ':' \
+ browser_version
print(' VNC image is available & downloading now... {0}'.format(
command))
try:
subprocess.call([command], shell=True, stdout=subprocess.PIPE)
vnc_image_available = True
except Exception:
traceback.print_exc(file=sys.stderr)
print(
'{0}} Image found but could not download.'.format(command))
sys.exit(1)
break
elif idx == len(version_tag):
print("{0} Image is not available.".format(image_name))
vnc_image_available = False
else:
pass
return vnc_image_available
def reload_selenoid_config():
"""
Function runs command to refresh selenoid configuration
:return: true if command execution for selenoid reload is successful
else false
"""
command = 'docker kill -s HUP selenoid'
reload_successful = False
try:
subprocess.call([command], shell=True, stdout=subprocess.PIPE)
print(" Selenoid Configuration is reloaded.")
reload_successful = True
except Exception:
traceback.print_exc(file=sys.stderr)
print('Error while reloading selenoid configuration.')
sys.exit(1)
return reload_successful
def edit_browsers_json(browser_name, browser_version):
"""
Function edits browsers.json which is used by selenoid to
load browser configuration.
Default path for this file is
"user_home_dir + '/.aerokube/selenoid/browsers.json'"
Currently this is hardcoded, might need to modify
if we want to pass customize browsers.json
:param browser_name:
:param browser_version:
:return:
"""
file_edited = True
# Read existing browsers.json
json_file = open(file_path, 'r')
existing_data = json.load(json_file)
updated_data = None
# Update data for new browser images
if browser_name.lower() == 'chrome':
version_data = existing_data['chrome']['versions']
if browser_version in version_data.keys():
print(" {0}:{1} is already updated in browsers.json.".format(
browser_name, browser_version))
file_edited = True
else:
data_to_insert = dict(
{browser_version: {
'image': 'selenoid/vnc_chrome:' + browser_version,
'port': '4444', 'path': '/'}})
(existing_data['chrome']['versions']).update(data_to_insert)
updated_data = existing_data
print(updated_data)
elif browser_name.lower() == 'firefox':
version_data = existing_data['firefox']['versions']
if browser_version in version_data.keys():
print(" {0}:{1} is already updated in browsers.json.".format(
browser_name, browser_version))
file_edited = True
else:
data_to_insert = dict(
{browser_version: {
'image': 'selenoid/vnc_firefox:' + browser_version,
'port': '4444', 'path': '/wd/hub'}})
(existing_data['firefox']['versions']).update(data_to_insert)
updated_data = existing_data
else:
print("Browser version not matched")
file_edited = False
# Write updated data in browsers.json
if updated_data is not None:
json_file = open(file_path, 'w')
json.dump(updated_data, json_file)
print(" 'browsers.json' is updated for {0} {1}".format(
browser_name, browser_version))
file_edited = True
return file_edited
# Main Program starts here
# Read command line arguments & get list of browser_name, executable path.
args = vars(read_command_line())
# Get path path for browsers.json
user_home_dir = os.getenv("HOME")
file_path = user_home_dir + '/.aerokube/selenoid/browsers.json'
print("***** Updating '{0}' for new browser versions.*****".format(file_path))
# Iterate over arguments passed
for browser, executable_path in args.items():
if executable_path is not None:
# Get browser name
browser_name = browser
# Get browser version
browser_version = get_browser_version(browser, executable_path)
print(
" Browser version for {0} is {1} in current executable path ".
format(browser_name, browser_version))
# Download vnc browser image.
download_new_image = check_and_download_vnc_browser_image(
browser_name, browser_version)
# If browser vnc image is available, then edit browsers.json
if download_new_image:
if edit_browsers_json(browser_name, browser_version):
print(
" File 'browsers.json' is updated for {0} - {1} \n".format(
browser_name, browser_version))
else:
print(
" File 'browsers.json' can NOT be updated for {0} - {1} \n"
.format(browser_name, browser_version))
else:
print(" Browser image is not available for {0}, {1}".format(
browser_name, browser_version))
# Reload selenoid configuration
if reload_selenoid_config():
print(
"***** Updated '{0}' for new browser versions.*****".format(file_path))
+7 -16
View File
@@ -11,15 +11,11 @@
#
##########################################################################
import builtins
import logging
import os
import sys
import json
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# We need to include the root directory in sys.path to ensure that we can
# find everything we need when running in the standalone runtime.
@@ -27,7 +23,7 @@ root = os.path.dirname(os.path.realpath(__file__))
if sys.path[0] != root:
sys.path.insert(0, root)
from pgadmin.utils import env, IS_PY2, IS_WIN, fs_short_path
from pgadmin.utils import env, IS_WIN, fs_short_path
##########################################################################
# Application settings
@@ -51,7 +47,7 @@ APP_ICON = 'pg-icon'
# Application version number components
APP_RELEASE = 4
APP_REVISION = 21
APP_REVISION = 22
# Application version suffix, e.g. 'beta1', 'dev'. Usually an empty string
# for GA releases.
@@ -60,7 +56,7 @@ APP_SUFFIX = ''
# Numeric application version for upgrade checks. Should be in the format:
# [X]XYYZZ, where X is the release version, Y is the revision, with a leading
# zero if needed, and Z represents the suffix, with a leading zero if needed
APP_VERSION_INT = 42100
APP_VERSION_INT = 42200
# DO NOT CHANGE!
# The application version string, constructed from the components
@@ -566,14 +562,9 @@ try:
except ImportError:
pass
# SUPPORT_SSH_TUNNEL can be override in local config file and if that
# setting is False in local config then we should not check the Python version.
if (SUPPORT_SSH_TUNNEL is True and
((sys.version_info[0] == 2 and sys.version_info[1] < 7) or
(sys.version_info[0] == 3 and sys.version_info[1] < 4))):
SUPPORT_SSH_TUNNEL = False
ALLOW_SAVE_TUNNEL_PASSWORD = False
# Override DEFAULT_SERVE value from environment variable.
if 'PGADMIN_CONFIG_DEFAULT_SERVER' in os.environ:
DEFAULT_SERVER = os.environ['PGADMIN_CONFIG_DEFAULT_SERVER']
# Disable USER_INACTIVITY_TIMEOUT when SERVER_MODE=False
if not SERVER_MODE:
+98 -97
View File
@@ -11,19 +11,19 @@
a webserver, this will provide the WSGI interface, otherwise, we're going
to start a web server."""
import os
import sys
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
if sys.version_info < (3, 4):
raise Exception('This application must be run under Python 3.4 or later.')
import builtins
import os
# We need to include the root directory in sys.path to ensure that we can
# find everything we need when running in the standalone runtime.
root = os.path.dirname(os.path.realpath(__file__))
if sys.path[0] != root:
sys.path.insert(0, root)
if sys.path[0] != os.path.dirname(os.path.realpath(__file__)):
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
# Grab the SERVER_MODE if it's been set by the runtime
if 'SERVER_MODE' in globals():
@@ -31,38 +31,13 @@ if 'SERVER_MODE' in globals():
else:
builtins.SERVER_MODE = None
# Set null device file path to stdout, stdin, stderr if they are None
for _name in ('stdin', 'stdout', 'stderr'):
if getattr(sys, _name) is None:
setattr(sys, _name, open(os.devnull,
'r' if _name == 'stdin' else 'w'))
import config
from pgadmin import create_app
from pgadmin.utils import u, fs_encoding, file_quote
if config.DEBUG:
from pgadmin.utils.javascript.javascript_bundler import \
JavascriptBundler, JsState
# Get the config database schema version. We store this in pgadmin.model
# as it turns out that putting it in the config files isn't a great idea
from pgadmin.model import SCHEMA_VERSION
config.SETTINGS_SCHEMA_VERSION = SCHEMA_VERSION
##########################################################################
# Sanity checks
##########################################################################
# Check if the database exists. If it does not, create it.
if not os.path.isfile(config.SQLITE_PATH):
setupfile = os.path.join(
os.path.dirname(os.path.realpath(u(__file__, fs_encoding))),
u'setup.py'
)
exec(open(file_quote(setupfile), 'r').read())
##########################################################################
# Support reverse proxying
@@ -70,7 +45,7 @@ if not os.path.isfile(config.SQLITE_PATH):
class ReverseProxied(object):
def __init__(self, app):
self.app = app
# https://werkzeug.palletsprojects.com/en/0.15.x/middleware/proxy_fix/#module-werkzeug.middleware.proxy_fix
# https://werkzeug.palletsprojects.com/en/0.15.x/middleware/proxy_fix
try:
from werkzeug.middleware.proxy_fix import ProxyFix
self.app = ProxyFix(app,
@@ -97,72 +72,31 @@ class ReverseProxied(object):
##########################################################################
# Server startup
# Sanity checks
##########################################################################
config.SETTINGS_SCHEMA_VERSION = SCHEMA_VERSION
# Build Javascript files
if config.DEBUG:
javascriptBundler = JavascriptBundler()
javascriptBundler.bundle()
# Check if the database exists. If it does not, create it.
if not os.path.isfile(config.SQLITE_PATH):
setup_py = os.path.join(
os.path.dirname(os.path.realpath(u(__file__, fs_encoding))),
u'setup.py'
)
exec(open(file_quote(setup_py), 'r').read())
# Create the app!
##########################################################################
# Create the app and configure it. It is created outside main so that
# it can be imported
##########################################################################
app = create_app()
app.debug = False
if config.SERVER_MODE:
app.wsgi_app = ReverseProxied(app.wsgi_app)
if config.DEBUG:
app.debug = True
else:
app.debug = False
# respond to JS
if config.DEBUG and javascriptBundler.report() == JsState.NONE:
app.logger.error(
"Unable to generate javascript.\n"
"To run the app ensure that yarn install command runs successfully"
)
raise Exception("No generated javascript, aborting")
# Start the web server. The port number should have already been set by the
# runtime if we're running in desktop mode, otherwise we'll just use the
# Flask default.
PGADMIN_RUNTIME = False
if 'PGADMIN_INT_PORT' in globals():
app.logger.debug(
'Running under the desktop runtime, port: %s',
globals()['PGADMIN_INT_PORT']
)
server_port = int(globals()['PGADMIN_INT_PORT'])
PGADMIN_RUNTIME = True
elif 'PGADMIN_INT_PORT' in os.environ:
port = os.environ['PGADMIN_INT_PORT']
app.logger.debug(
'Not running under the desktop runtime, port: %s',
port
)
server_port = int(port)
else:
app.logger.debug(
'Not running under the desktop runtime, port: %s',
config.DEFAULT_SERVER_PORT
)
server_port = config.DEFAULT_SERVER_PORT
# Let the application save the status about the runtime for using it later.
app.PGADMIN_RUNTIME = PGADMIN_RUNTIME
# Set the key if appropriate
if 'PGADMIN_INT_KEY' in globals():
app.PGADMIN_INT_KEY = globals()['PGADMIN_INT_KEY']
app.logger.debug("Desktop security key: %s" % app.PGADMIN_INT_KEY)
else:
app.PGADMIN_INT_KEY = ''
# Authentication sources
app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
app.PGADMIN_SUPPORTED_AUTH_SOURCE = ['internal', 'ldap']
if len(config.AUTHENTICATION_SOURCES) > 0:
app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
else:
@@ -171,13 +105,73 @@ else:
app.logger.debug(
"Authentication Source: %s" % app.PGADMIN_DEFAULT_AUTH_SOURCE)
# Output a startup message if we're not under the runtime and startup.
# If we're under WSGI, we don't need to worry about this
if __name__ == '__main__':
if not PGADMIN_RUNTIME:
# Start the web server. The port number should have already been set by the
# runtime if we're running in desktop mode, otherwise we'll just use the
# Flask default.
app.PGADMIN_RUNTIME = False
config.EFFECTIVE_SERVER_PORT = None
if 'PGADMIN_INT_PORT' in globals():
app.logger.debug(
'Running under the desktop runtime, port: %s',
globals()['PGADMIN_INT_PORT']
)
config.EFFECTIVE_SERVER_PORT = int(globals()['PGADMIN_INT_PORT'])
app.PGADMIN_RUNTIME = True
elif 'PGADMIN_INT_PORT' in os.environ:
port = os.environ['PGADMIN_INT_PORT']
app.logger.debug(
'Not running under the desktop runtime, port: %s',
port
)
config.EFFECTIVE_SERVER_PORT = int(port)
else:
app.logger.debug(
'Not running under the desktop runtime, port: %s',
config.DEFAULT_SERVER_PORT
)
config.EFFECTIVE_SERVER_PORT = config.DEFAULT_SERVER_PORT
# Set the key if appropriate
if 'PGADMIN_INT_KEY' in globals():
app.PGADMIN_INT_KEY = globals()['PGADMIN_INT_KEY']
app.logger.debug("Desktop security key: %s" % app.PGADMIN_INT_KEY)
else:
app.PGADMIN_INT_KEY = ''
##########################################################################
# The entry point
##########################################################################
def main():
# Set null device file path to stdout, stdin, stderr if they are None
for _name in ('stdin', 'stdout', 'stderr'):
if getattr(sys, _name) is None:
setattr(sys, _name,
open(os.devnull, 'r' if _name == 'stdin' else 'w'))
# Build Javascript files when DEBUG
if config.DEBUG:
from pgadmin.utils.javascript.javascript_bundler import \
JavascriptBundler, JsState
app.debug = True
javascriptBundler = JavascriptBundler()
javascriptBundler.bundle()
if javascriptBundler.report() == JsState.NONE:
app.logger.error(
"Unable to generate javascript.\n"
"To run the app ensure that yarn install command runs "
"successfully"
)
raise Exception("No generated javascript, aborting")
# Output a startup message if we're not under the runtime and startup.
# If we're under WSGI, we don't need to worry about this
if not app.PGADMIN_RUNTIME:
print(
"Starting %s. Please navigate to http://%s:%d in your browser." %
(config.APP_NAME, config.DEFAULT_SERVER, server_port)
(config.APP_NAME, config.DEFAULT_SERVER,
config.EFFECTIVE_SERVER_PORT)
)
sys.stdout.flush()
else:
@@ -203,9 +197,9 @@ if __name__ == '__main__':
try:
app.run(
host=config.DEFAULT_SERVER,
port=server_port,
port=config.EFFECTIVE_SERVER_PORT,
use_reloader=(
(not PGADMIN_RUNTIME) and app.debug and
(not app.PGADMIN_RUNTIME) and app.debug and
os.environ.get("WERKZEUG_RUN_MAIN") is not None
),
threaded=config.THREADED_MODE
@@ -213,3 +207,10 @@ if __name__ == '__main__':
except IOError:
app.logger.error("Error starting the app server: %s", sys.exc_info())
##########################################################################
# Server startup
##########################################################################
if __name__ == '__main__':
main()
+5 -5
View File
@@ -10,15 +10,15 @@
import os
import sys
if sys.version_info < (3, 4):
raise Exception('This application must be run under Python 3.4 or later.')
import builtins
root = os.path.dirname(os.path.realpath(__file__))
if sys.path[0] != root:
sys.path.insert(0, root)
if sys.version_info[0] >= 3:
import builtins
else:
import __builtin__ as builtins
# Ensure the global server mode is set.
builtins.SERVER_MODE = True
+4 -10
View File
@@ -43,12 +43,9 @@ from pgadmin import authenticate
# If script is running under python3, it will not have the xrange function
# defined
winreg = None
if sys.version_info[0] >= 3:
xrange = range
if os.name == 'nt':
import winreg
elif os.name == 'nt':
import _winreg as winreg
xrange = range
if os.name == 'nt':
import winreg
class PgAdmin(Flask):
@@ -522,10 +519,7 @@ def create_app(app_name=None):
pass
else:
# We use the postgres-winreg.ini file on non-Windows
try:
from configparser import ConfigParser
except ImportError:
from ConfigParser import ConfigParser # Python 2
from configparser import ConfigParser
registry = ConfigParser()
+3 -2
View File
@@ -15,7 +15,8 @@ from flask import current_app, flash
from flask_babelex import gettext
from flask_security import current_user
from flask_security.views import _security, _ctx
from flask_security.utils import config_value, get_post_logout_redirect
from flask_security.utils import config_value, get_post_logout_redirect, \
get_post_login_redirect
from flask import session
import config
@@ -60,7 +61,7 @@ def login():
return flask.redirect(get_post_logout_redirect())
session['_auth_source_manager_obj'] = auth_obj.as_dict()
return flask.redirect('/')
return flask.redirect(get_post_login_redirect())
flash(gettext(msg), 'danger')
return flask.redirect(get_post_logout_redirect())
+3 -6
View File
@@ -16,17 +16,13 @@ from ldap3.core.exceptions import LDAPSocketOpenError, LDAPBindError,\
LDAPInvalidScopeError, LDAPAttributeError, LDAPInvalidFilterError,\
LDAPStartTLSError, LDAPSSLConfigurationError
from flask_babelex import gettext
from urllib.parse import urlparse
from .internal import BaseAuthentication
from pgadmin.model import User, ServerGroup, db, Role
from flask import current_app
from pgadmin.tools.user_management import create_user
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
@@ -162,7 +158,8 @@ class LDAPAuthentication(BaseAuthentication):
search criteria."""
try:
search_base_dn = config.LDAP_SEARCH_BASE_DN
if search_base_dn is None or search_base_dn == '':
if search_base_dn is None or search_base_dn == '' or\
search_base_dn == '<Search-Base-DN>':
search_base_dn = config.LDAP_BASE_DN
self.conn.search(search_base=search_base_dn,
search_filter=config.LDAP_SEARCH_FILTER,
+9 -1
View File
@@ -29,7 +29,7 @@ from flask_security.recoverable import reset_password_token_status, \
from flask_security.signals import reset_password_instructions_sent
from flask_security.utils import config_value, do_flash, get_url, \
get_message, slash_url_suffix, login_user, send_mail
from flask_security.views import _security, _commit, default_render_json, _ctx
from flask_security.views import _security, _commit, _ctx
from werkzeug.datastructures import MultiDict
import config
@@ -52,6 +52,14 @@ try:
except ImportError as e:
import urllib2 as urlreq
try:
from flask_security.views import default_render_json
except ImportError as e:
# Support Flask-Security-Too == 3.2
import sys
if sys.version_info < (3, 8):
from flask_security.views import _render_json as default_render_json
MODULE_NAME = 'browser'
@@ -866,7 +866,10 @@ class ServerNode(PGChildNodeView):
connected=connected,
server_type=manager.server_type
if manager and manager.server_type
else 'pg'
else 'pg',
version=manager.version
if manager and manager.version
else None
)
)
@@ -456,30 +456,33 @@ class DatabaseView(PGChildNodeView):
from pgadmin.utils.driver import get_driver
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
conn = manager.connection(did=did, auto_reconnect=True)
status, errmsg = conn.connect()
if not status:
current_app.logger.error(
"Could not connected to database(#{0}).\nError: {1}".format(
did, errmsg
already_connected = conn.connected()
if not already_connected:
status, errmsg = conn.connect()
if not status:
current_app.logger.error(
"Could not connected to database(#{0}).\nError: {1}"
.format(
did, errmsg
)
)
)
return internal_server_error(errmsg)
else:
current_app.logger.info('Connection Established for Database Id: \
%s' % (did))
return make_json_response(
success=1,
info=_("Database connected."),
data={
'icon': 'pg-icon-database',
'connected': True,
'info_prefix': '{0}/{1}'.
format(Server.query.filter_by(id=sid)[0].name, conn.db)
}
)
return internal_server_error(errmsg)
else:
current_app.logger.info(
'Connection Established for Database Id: \
%s' % (did)
)
return make_json_response(
success=1,
info=_("Database connected."),
data={
'icon': 'pg-icon-database',
'already_connected': already_connected,
'connected': True,
'info_prefix': '{0}/{1}'.
format(Server.query.filter_by(id=sid)[0].name, conn.db)
}
)
def disconnect(self, gid, sid, did):
"""Disconnect the database."""
@@ -21,10 +21,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class CastModule(CollectionNodeModule):
@@ -424,7 +420,7 @@ class CastView(PGChildNodeView):
try:
sql, name = self.get_sql(gid, sid, did, data, cid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
status, res = self.conn.execute_scalar(sql)
if not status:
@@ -521,7 +517,7 @@ class CastView(PGChildNodeView):
data = request.args
sql, name = self.get_sql(gid, sid, did, data, cid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
sql = sql.strip('\n').strip(' ')
if sql == '':
@@ -14,12 +14,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsCreateTestCase(BaseTestGenerator):
@@ -14,13 +14,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsCreateGetFunctionsTestCase(BaseTestGenerator):
@@ -14,13 +14,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsCreateGettypeTestCase(BaseTestGenerator):
@@ -15,13 +15,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsDeleteTestCase(BaseTestGenerator):
@@ -8,7 +8,6 @@
##########################################################################
from __future__ import print_function
import json
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
@@ -16,13 +15,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsMultipleDeleteTestCase(BaseTestGenerator):
@@ -14,13 +14,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsGetTestCase(BaseTestGenerator):
@@ -15,12 +15,6 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
class CastsGetDependentsAndDependencyTestCase(BaseTestGenerator):
@@ -1,3 +1,12 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
@@ -5,13 +14,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsGetNodeTestCase(BaseTestGenerator):
@@ -15,12 +15,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsGetSqlTestCase(BaseTestGenerator):
@@ -9,20 +9,13 @@
from __future__ import print_function
import json
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as cast_utils
import sys
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class CastsPutTestCase(BaseTestGenerator):
@@ -20,10 +20,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class EventTriggerModule(CollectionNodeModule):
@@ -446,7 +442,7 @@ class EventTriggerView(PGChildNodeView):
try:
sql = self.get_sql(data, etid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
sql = sql.strip('\n').strip(' ')
if sql != "":
@@ -573,7 +569,7 @@ class EventTriggerView(PGChildNodeView):
try:
sql = self.get_sql(data, etid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
sql = sql.strip('\n').strip(' ')
sql = re.sub('\n{2,}', '\n\n', sql)
@@ -9,8 +9,6 @@
import json
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import \
@@ -21,11 +19,7 @@ from regression import parent_node_dict
from regression import trigger_funcs_utils
from regression.python_test_utils import test_utils as utils
from . import utils as event_trigger_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class EventTriggerAddTestCase(BaseTestGenerator):
@@ -8,8 +8,6 @@
##########################################################################
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import \
@@ -20,11 +18,7 @@ from regression import parent_node_dict
from regression import trigger_funcs_utils
from regression.python_test_utils import test_utils as utils
from . import utils as event_trigger_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class EventTriggerDeleteTestCase(BaseTestGenerator):
@@ -8,7 +8,6 @@
##########################################################################
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
@@ -20,11 +19,7 @@ from regression import parent_node_dict
from regression import trigger_funcs_utils
from regression.python_test_utils import test_utils as utils
from . import utils as event_trigger_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class EventTriggerFunctionsTestCase(BaseTestGenerator):
@@ -8,7 +8,6 @@
##########################################################################
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import \
@@ -19,11 +18,7 @@ from regression import parent_node_dict
from regression import trigger_funcs_utils
from regression.python_test_utils import test_utils as utils
from . import utils as event_trigger_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class EventTriggerGetTestCase(BaseTestGenerator):
@@ -9,8 +9,6 @@
import json
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import \
@@ -21,11 +19,7 @@ from regression import parent_node_dict
from regression import trigger_funcs_utils
from regression.python_test_utils import test_utils as utils
from . import utils as event_trigger_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class EventTriggerPutTestCase(BaseTestGenerator):
@@ -8,7 +8,6 @@
##########################################################################
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
utils as schema_utils
from pgadmin.browser.server_groups.servers.databases.tests import \
@@ -19,11 +18,7 @@ from regression import parent_node_dict
from regression import trigger_funcs_utils
from regression.python_test_utils import test_utils as utils
from . import utils as event_trigger_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class EventTriggerGetSqlTestCase(BaseTestGenerator):
@@ -22,27 +22,6 @@ from pgadmin.utils.ajax import make_json_response, \
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
# As unicode type is not available in python3
# If we check a variable is "isinstance(variable, str)
# it breaks in python 3 as variable type is not string its unicode.
# We assign basestring as str type if it is python3, unicode
# if it is python2.
try:
unicode = unicode
except NameError:
# 'unicode' is undefined, must be Python 3
str = str
unicode = str
bytes = bytes
basestring = (str, bytes)
else:
# 'unicode' exists, must be Python 2
str = str
unicode = unicode
bytes = str
basestring = basestring
class ExtensionModule(CollectionNodeModule):
"""
@@ -315,7 +294,7 @@ class ExtensionView(PGChildNodeView):
try:
SQL, name = self.getSQL(gid, sid, data, did, eid)
# Most probably this is due to error
if not isinstance(SQL, (str, unicode)):
if not isinstance(SQL, str):
return SQL
SQL = SQL.strip('\n').strip(' ')
status, res = self.conn.execute_dict(SQL)
@@ -393,7 +372,7 @@ class ExtensionView(PGChildNodeView):
try:
SQL, name = self.getSQL(gid, sid, data, did, eid)
# Most probably this is due to error
if not isinstance(SQL, (str, unicode)):
if not isinstance(SQL, str):
return SQL
SQL = SQL.strip('\n').strip(' ')
if SQL == '':
@@ -7,18 +7,12 @@
#
##########################################################################
import sys
import six
from pgadmin.browser.server_groups.servers\
.databases.external_tables import ExternalTablesModule
from pgadmin.utils.route import BaseTestGenerator
if sys.version_info < (3, 3):
from mock import MagicMock, Mock
else:
from unittest.mock import MagicMock, Mock
from unittest.mock import MagicMock, Mock
class TestExternalTablesModule(BaseTestGenerator):
@@ -8,16 +8,11 @@
##########################################################################
import os
import sys
from pgadmin.browser.server_groups.servers.databases.external_tables import \
ExternalTablesView
from pgadmin.utils.route import BaseTestGenerator
if sys.version_info < (3, 3):
from mock import MagicMock, patch
else:
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock, patch
class TestExternalTablesView(BaseTestGenerator):
@@ -6,18 +6,13 @@
# This software is released under the PostgreSQL Licence
#
##########################################################################
import sys
from pgadmin.browser.server_groups.servers.databases \
.external_tables import Properties
from pgadmin.browser.server_groups.servers.databases.external_tables \
.properties import PropertiesException, PropertiesTableNotFoundException
from pgadmin.utils.route import BaseTestGenerator
if sys.version_info < (3, 3):
from mock import MagicMock, patch
else:
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock, patch
class TestProperties(BaseTestGenerator):
@@ -7,17 +7,11 @@
#
##########################################################################
import sys
from pgadmin.browser.server_groups.servers.databases \
.external_tables.reverse_engineer_ddl import \
ReverseEngineerDDL, ReverseEngineerDDLException
from pgadmin.utils.route import BaseTestGenerator
if sys.version_info < (3, 3):
from mock import MagicMock
else:
from unittest.mock import MagicMock
from unittest.mock import MagicMock
class TestReverseEngineerDDL(BaseTestGenerator):
@@ -23,10 +23,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class ForeignDataWrapperModule(CollectionNodeModule):
@@ -467,7 +463,7 @@ class ForeignDataWrapperView(PGChildNodeView):
try:
sql, name = self.get_sql(gid, sid, data, did, fid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
status, res = self.conn.execute_scalar(sql)
if not status:
@@ -575,7 +571,7 @@ class ForeignDataWrapperView(PGChildNodeView):
try:
sql, name = self.get_sql(gid, sid, data, did, fid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
if sql == '':
sql = "--modified SQL"
@@ -23,10 +23,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class ForeignServerModule(CollectionNodeModule):
@@ -466,7 +462,7 @@ class ForeignServerView(PGChildNodeView):
try:
sql, name = self.get_sql(gid, sid, data, did, fid, fsid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
sql = sql.strip('\n').strip(' ')
status, res = self.conn.execute_scalar(sql)
@@ -579,7 +575,7 @@ class ForeignServerView(PGChildNodeView):
try:
sql, name = self.get_sql(gid, sid, data, did, fid, fsid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
if sql == '':
sql = "--modified SQL"
@@ -23,10 +23,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class UserMappingModule(CollectionNodeModule):
@@ -473,7 +469,7 @@ class UserMappingView(PGChildNodeView):
try:
sql, name = self.get_sql(gid, sid, data, did, fid, fsid, umid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
sql = sql.strip('\n').strip(' ')
status, res = self.conn.execute_scalar(sql)
@@ -599,7 +595,7 @@ class UserMappingView(PGChildNodeView):
try:
sql, name = self.get_sql(gid, sid, data, did, fid, fsid, umid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
if sql == '':
sql = "--modified SQL"
@@ -23,10 +23,6 @@ from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
from pgadmin.utils import IS_PY2
# If we are in Python3
if not IS_PY2:
unicode = str
class LanguageModule(CollectionNodeModule):
@@ -420,7 +416,7 @@ class LanguageView(PGChildNodeView):
try:
sql, name = self.get_sql(data, lid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
sql = sql.strip('\n').strip(' ')
status, res = self.conn.execute_dict(sql)
@@ -577,7 +573,7 @@ class LanguageView(PGChildNodeView):
try:
sql, name = self.get_sql(data, lid)
# Most probably this is due to error
if not isinstance(sql, (str, unicode)):
if not isinstance(sql, str):
return sql
if sql == '':
sql = "--modified SQL"
@@ -11,7 +11,6 @@ from __future__ import print_function
import json
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
@@ -19,11 +18,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as language_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class LanguagesAddTestCase(BaseTestGenerator):
@@ -8,7 +8,6 @@
##########################################################################
from __future__ import print_function
import sys
import uuid
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
@@ -16,11 +15,7 @@ from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as language_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class LanguagesDeleteTestCase(BaseTestGenerator):
@@ -10,18 +10,13 @@
from __future__ import print_function
import uuid
import sys
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from regression.python_test_utils import test_utils as utils
from . import utils as language_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class LanguagesGetTestCase(BaseTestGenerator):
@@ -10,18 +10,13 @@
from __future__ import print_function
import uuid
import sys
from . import utils as language_utils
from regression.python_test_utils import test_utils as utils
from regression import parent_node_dict
from pgadmin.utils.route import BaseTestGenerator
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class LanguagesGetFunctionAndTemplateTestCase(BaseTestGenerator):
@@ -11,18 +11,13 @@ from __future__ import print_function
import json
import uuid
import sys
from regression.python_test_utils import test_utils as utils
from pgadmin.utils.route import BaseTestGenerator
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
from regression import parent_node_dict
from . import utils as language_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class LanguagesPutTestCase(BaseTestGenerator):
@@ -10,18 +10,13 @@
from __future__ import print_function
import uuid
import sys
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from . import utils as language_utils
from regression.python_test_utils import test_utils as utils
from pgadmin.browser.server_groups.servers.databases.tests import \
utils as database_utils
if sys.version_info < (3, 3):
from mock import patch
else:
from unittest.mock import patch
from unittest.mock import patch
class LanguagesGetSql(BaseTestGenerator):
@@ -10,7 +10,7 @@ SELECT
(SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup,
indkey, coll.collname, nspc.nspname as collnspname , attoptions,
-- Start pgAdmin4, added to save time on client side parsing
CASE WHEN length(coll.collname) > 0 AND length(nspc.nspname) > 0 THEN
CASE WHEN length(coll.collname::text) > 0 AND length(nspc.nspname::text) > 0 THEN
concat(quote_ident(nspc.nspname),'.',quote_ident(coll.collname))
ELSE '' END AS collspcname,
CASE WHEN strpos(format_type(ty.oid,att.atttypmod), '.') > 0 THEN
@@ -20,7 +20,6 @@ from config import PG_DEFAULT_DRIVER
from pgadmin.browser.server_groups.servers.databases.schemas.utils \
import SchemaChildModule
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.utils import IS_PY2
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.compile_template_name import compile_template_path
@@ -28,10 +27,6 @@ from pgadmin.utils.driver import get_driver
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
# If we are in Python3
if not IS_PY2:
unicode = str
class CollationModule(SchemaChildModule):
"""
@@ -597,7 +592,7 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
)
SQL, name = self.get_sql(gid, sid, data, scid, coid)
# Most probably this is due to error
if not isinstance(SQL, (str, unicode)):
if not isinstance(SQL, str):
return SQL
SQL = SQL.strip('\n').strip(' ')
status, res = self.conn.execute_scalar(SQL)
@@ -651,7 +646,7 @@ class CollationView(PGChildNodeView, SchemaDiffObjectCompare):
try:
SQL, name = self.get_sql(gid, sid, data, scid, coid)
# Most probably this is due to error
if not isinstance(SQL, (str, unicode)):
if not isinstance(SQL, str):
return SQL
if SQL == '':
SQL = "--modified SQL"
@@ -1,7 +1,7 @@
SELECT --nspname, collname,
CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
CASE WHEN length(nspname::text) > 0 AND length(collname::text) > 0 THEN
concat(quote_ident(nspname), '.', quote_ident(collname))
ELSE '' END AS copy_collation
FROM pg_collation c, pg_namespace n
WHERE c.collnamespace=n.oid
ORDER BY nspname, collname;
ORDER BY nspname, collname;
@@ -22,7 +22,6 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils import \
from pgadmin.browser.server_groups.servers.databases.utils import \
parse_sec_labels_from_db
from pgadmin.browser.utils import PGChildNodeView
from pgadmin.utils import IS_PY2
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
make_response as ajax_response, gone
from pgadmin.utils.compile_template_name import compile_template_path
@@ -30,10 +29,6 @@ from pgadmin.utils.driver import get_driver
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
# If we are in Python3
if not IS_PY2:
unicode = str
class DomainModule(SchemaChildModule):
"""
@@ -554,7 +549,7 @@ AND relkind != 'c'))"""
data = self.request
SQL, name = self.get_sql(gid, sid, data, scid)
# Most probably this is due to error
if not isinstance(SQL, (str, unicode)):
if not isinstance(SQL, str):
return SQL
status, res = self.conn.execute_scalar(SQL)
@@ -670,7 +665,7 @@ AND relkind != 'c'))"""
SQL, name = self.get_sql(gid, sid, self.request, scid, doid)
# Most probably this is due to error
if not isinstance(SQL, (str, unicode)):
if not isinstance(SQL, str):
return SQL
status, res = self.conn.execute_scalar(SQL)
@@ -784,7 +779,7 @@ AND relkind != 'c'))"""
try:
SQL, name = self.get_sql(gid, sid, self.request, scid, doid)
# Most probably this is due to error
if not isinstance(SQL, (str, unicode)):
if not isinstance(SQL, str):
return SQL
if SQL == '':
SQL = "--modified SQL"
@@ -1,5 +1,5 @@
SELECT --nspname, collname,
CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
CASE WHEN length(nspname::text) > 0 AND length(collname::text) > 0 THEN
concat(nspname, '."', collname,'"')
ELSE '' END AS copy_collation
FROM
@@ -1,7 +1,7 @@
SELECT
d.oid, d.typname as name, d.typbasetype, format_type(b.oid,NULL) as basetype, pg_get_userbyid(d.typowner) as owner,
c.oid AS colloid, format_type(b.oid, d.typtypmod) AS fulltype,
CASE WHEN length(cn.nspname) > 0 AND length(c.collname) > 0 THEN
CASE WHEN length(cn.nspname::text) > 0 AND length(c.collname::text) > 0 THEN
concat(cn.nspname, '."', c.collname,'"')
ELSE '' END AS collname,
d.typtypmod, d.typnotnull, d.typdefault, d.typndims, d.typdelim, bn.nspname as basensp,
@@ -1,5 +1,5 @@
SELECT --nspname, collname,
CASE WHEN length(nspname) > 0 AND length(collname) > 0 THEN
CASE WHEN length(nspname::text) > 0 AND length(collname::text) > 0 THEN
concat(nspname, '."', collname,'"')
ELSE '' END AS copy_collation
FROM
@@ -2,7 +2,7 @@ SELECT
d.oid, d.typname as name, d.typbasetype, format_type(b.oid,NULL) as basetype,
pg_get_userbyid(d.typowner) as owner,
c.oid AS colloid, format_type(b.oid, d.typtypmod) AS fulltype,
CASE WHEN length(cn.nspname) > 0 AND length(c.collname) > 0 THEN
CASE WHEN length(cn.nspname::text) > 0 AND length(c.collname::text) > 0 THEN
concat(cn.nspname, '."', c.collname,'"')
ELSE '' END AS collname,
d.typtypmod, d.typnotnull, d.typdefault, d.typndims, d.typdelim, bn.nspname as basensp,
Loaded 100 of 414 files, more files were not shown because too many files have changed in this diff. Show more