mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-10-28 23:50:04 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1347c89d61 | ||
|
|
b1cbcc7ef6 | ||
|
|
22c3a2649b | ||
|
|
2bb0b25688 | ||
|
|
2aefc6361e | ||
|
|
83cb01b8cd | ||
|
|
d42b712ee4 | ||
|
|
fec458dd6a | ||
|
|
9b8902dfb8 | ||
|
|
4a8037fc6a | ||
|
|
d927a517aa | ||
|
|
96939ba985 | ||
|
|
414b074bad | ||
|
|
7b1cac6914 | ||
|
|
4aaacfd5b0 | ||
|
|
52187306ce | ||
|
|
0e799b16b0 | ||
|
|
569d05df4e | ||
|
|
eac5fe5157 | ||
|
|
5337514c63 | ||
|
|
d1bdb178e2 | ||
|
|
9f445dc052 | ||
|
|
d58c33dec0 | ||
|
|
0f56c25893 | ||
|
|
762784d2b5 | ||
|
|
6d6cd19b37 | ||
|
|
c0451cd454 | ||
|
|
0620fafb6c | ||
|
|
a9a1a975a6 | ||
|
|
8a06a836f4 | ||
|
|
dba5761ad0 | ||
|
|
8ec1d4c9eb | ||
|
|
46e9924ebb | ||
|
|
12a7ce54d9 | ||
|
|
9d08776824 | ||
|
|
073d90c4a6 | ||
|
|
7d4ddc3910 | ||
|
|
1294c089a8 | ||
|
|
b64896f558 | ||
|
|
e73e2d2502 | ||
|
|
9338bdcb3a | ||
|
|
d68e6bd892 | ||
|
|
057a2b2312 | ||
|
|
46d186a49f | ||
|
|
7164c677de | ||
|
|
6ad46e1860 | ||
|
|
a662d866af | ||
|
|
a0940fd145 | ||
|
|
f61448eea2 | ||
|
|
943495de31 | ||
|
|
059f1e38cc | ||
|
|
370094274c | ||
|
|
04d6d4e2cc | ||
|
|
cf31d0187b | ||
|
|
f1963401d6 | ||
|
|
94bd1f1680 | ||
|
|
908e156113 | ||
|
|
5fe7813f9f | ||
|
|
d61b8eb1b3 | ||
|
|
0fc2afb829 | ||
|
|
cc2e3ece7a | ||
|
|
5656f756e6 | ||
|
|
9bdf900b25 | ||
|
|
0ec60a6f85 | ||
|
|
70e24ba059 | ||
|
|
ad80217593 | ||
|
|
7dd00a1494 | ||
|
|
109051e1d5 | ||
|
|
86afec860f | ||
|
|
393741fd9d | ||
|
|
e8a4b46ba1 | ||
|
|
97be3d8179 | ||
|
|
505956d1fa | ||
|
|
f7ef86dced | ||
|
|
3138f36e05 |
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
@@ -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
|
||||
|
||||
@@ -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**
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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."
|
||||
|
||||
Executable → Regular
BIN
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 |
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 119 KiB |
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;;
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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,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)"
|
||||
@@ -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}"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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'],
|
||||
},
|
||||
|
||||
)
|
||||
@@ -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
@@ -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
|
||||
Executable
+112
@@ -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}/"
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
|
||||
@@ -134,7 +134,7 @@ void MenuActions::onLog()
|
||||
|
||||
QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
|
||||
|
||||
m_logWindow->ReadLog();
|
||||
m_logWindow->LoadLog();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
+1
-7
@@ -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):
|
||||
|
||||
+1
-7
@@ -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):
|
||||
|
||||
+1
-8
@@ -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):
|
||||
|
||||
-6
@@ -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):
|
||||
|
||||
+10
-7
@@ -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):
|
||||
|
||||
+1
-6
@@ -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)
|
||||
|
||||
+1
-7
@@ -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):
|
||||
|
||||
+1
-7
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-7
@@ -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):
|
||||
|
||||
+1
-6
@@ -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 == '':
|
||||
|
||||
+1
-7
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-7
@@ -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):
|
||||
|
||||
+2
-6
@@ -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"
|
||||
|
||||
+2
-6
@@ -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"
|
||||
|
||||
+2
-6
@@ -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"
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-6
@@ -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):
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
+2
-2
@@ -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
-1
@@ -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
-1
@@ -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
-1
@@ -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
-1
@@ -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
Reference in new issue
Block a user