Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
593d86d3f2 | ||
|
|
8e132eab08 | ||
|
|
324e3e74be | ||
|
|
7dca844cbe | ||
|
|
8029d9e65e | ||
|
|
cea41cb4a9 | ||
|
|
5eb1c57320 | ||
|
|
5462aeab11 | ||
|
|
a850852847 | ||
|
|
291ee5366c | ||
|
|
a1b48d2c64 | ||
|
|
913e92a96e | ||
|
|
b82e6dbdb8 | ||
|
|
6ded547a0d | ||
|
|
a7d40e238e | ||
|
|
ed1bd74301 | ||
|
|
1bd0a0edf5 | ||
|
|
7fac72cac5 | ||
|
|
d0310b669e | ||
|
|
62e6848dc8 | ||
|
|
1bc1ef7f17 | ||
|
|
ffb829e80c | ||
|
|
796a8a013a | ||
|
|
535739c0c7 | ||
|
|
72f0e87367 | ||
|
|
f278490540 | ||
|
|
76b0e3e9f7 | ||
|
|
98e86a8160 | ||
|
|
9e5487d5ad | ||
|
|
8c2e965f6e | ||
|
|
f8f00b4ecf | ||
|
|
4da4a05611 | ||
|
|
9ae9ccff16 | ||
|
|
eaa90ee8eb | ||
|
|
31bbdd6a12 | ||
|
|
974d395a48 | ||
|
|
a67f6e4f9c | ||
|
|
ed0c4037ad | ||
|
|
b562ab7681 | ||
|
|
3e35dc95e5 | ||
|
|
ddf5b33219 | ||
|
|
1c9badec9c | ||
|
|
8f3bdf1cf3 | ||
|
|
3b9e8e47ec | ||
|
|
b85831fb5f | ||
|
|
fd0ed81f7f | ||
|
|
b5c299c5ad | ||
|
|
5a253f9053 | ||
|
|
11d5613866 | ||
|
|
3984544bdb | ||
|
|
e226b2fa75 | ||
|
|
e8b192be3e | ||
|
|
8368eed645 | ||
|
|
28b637c99c | ||
|
|
53a5410337 | ||
|
|
8222bf6420 | ||
|
|
0998d349ca | ||
|
|
f3bde7b5f1 | ||
|
|
8fcf527632 | ||
|
|
4eb17afe4e | ||
|
|
d2577e32e6 | ||
|
|
e582ffca38 | ||
|
|
59649ca42c | ||
|
|
e2ac6187dc | ||
|
|
df9aaf19c2 | ||
|
|
275c671576 | ||
|
|
86bbc3a9e8 | ||
|
|
b3d49c61a5 | ||
|
|
7f947f146c | ||
|
|
e6bd085c15 | ||
|
|
52d0241a17 | ||
|
|
b53de0c31d | ||
|
|
19491d79a5 | ||
|
|
dd6ae193ff | ||
|
|
fbbbc36221 | ||
|
|
7f3e8596e3 | ||
|
|
103b08c9c5 | ||
|
|
99a7ada58a | ||
|
|
6415294782 | ||
|
|
79e6480513 | ||
|
|
cc5a7ea334 | ||
|
|
4b56962c1b | ||
|
|
0668a52c6b | ||
|
|
89e2f09b84 | ||
|
|
0fd9ee06bd | ||
|
|
3f73516f8c | ||
|
|
e3b1ef0b80 | ||
|
|
ae18b9a0ac | ||
|
|
b0af385ea0 | ||
|
|
0122cf9aac | ||
|
|
085a4f4abf | ||
|
|
ad0bcba99e | ||
|
|
7a05edc42a | ||
|
|
d2f93d6fad | ||
|
|
1466e414ec | ||
|
|
8f61944386 | ||
|
|
63df19ee1c | ||
|
|
93adf6884f | ||
|
|
36574b25b6 | ||
|
|
26506a9727 | ||
|
|
caeea7940a | ||
|
|
5b688cf949 | ||
|
|
7dd313f5fc | ||
|
|
1f70385a4e | ||
|
|
8129df42da | ||
|
|
082b968bbc | ||
|
|
2907a79dd7 | ||
|
|
46af290b85 | ||
|
|
26a758a0d6 | ||
|
|
9d006d0ec5 | ||
|
|
7a0bfecfc5 | ||
|
|
604937cf66 | ||
|
|
4f74609ecf | ||
|
|
3672013ddc | ||
|
|
9ad7476a34 | ||
|
|
23a12efd29 | ||
|
|
518b13c779 | ||
|
|
d9c20de31f | ||
|
|
d6400bbcae | ||
|
|
68a5027d15 | ||
|
|
48ec4085d2 | ||
|
|
e494b1520d | ||
|
|
aac0da4cbc | ||
|
|
48737e6a02 | ||
|
|
1122e06f48 | ||
|
|
e3dfe03a2a | ||
|
|
6a406f466d | ||
|
|
aa679e06b2 | ||
|
|
d2621282dc | ||
|
|
5ce2773658 | ||
|
|
43e127de31 | ||
|
|
87d08de3a0 | ||
|
|
536593bf8a | ||
|
|
eb2c554601 | ||
|
|
318d712c4f | ||
|
|
32d904058a | ||
|
|
56cf64ad22 | ||
|
|
dd7eb54e90 | ||
|
|
89fa85d650 | ||
|
|
099fea15ae | ||
|
|
74fd5dfe96 | ||
|
|
287a6628ed | ||
|
|
510dd5c047 | ||
|
|
f715373218 | ||
|
|
5820b9521e | ||
|
|
6fc6ec1cda | ||
|
|
a0893fe43b | ||
|
|
46ba0310fa | ||
|
|
ed0dc62b69 | ||
|
|
fb0bc65ced | ||
|
|
f57558fdb2 | ||
|
|
f93cfe8c4c | ||
|
|
7a22cff28c | ||
|
|
043025d1eb | ||
|
|
4cf8c2f300 | ||
|
|
937877e841 | ||
|
|
dd27e08a98 | ||
|
|
1fbf298d30 | ||
|
|
505a3ac960 | ||
|
|
310450cfa7 | ||
|
|
5f619ae40a | ||
|
|
28a4359020 | ||
|
|
f177d54f21 | ||
|
|
851c15b2d6 | ||
|
|
c0e30c93e5 | ||
|
|
645517d22d | ||
|
|
3983e2c13c | ||
|
|
f29db1a9cd | ||
|
|
c723b4584c | ||
|
|
b75c09d7c0 | ||
|
|
225c3e8f7e | ||
|
|
7edcca9b07 | ||
|
|
9174db2024 | ||
|
|
69e2ec806b | ||
|
|
04ce8b2c71 | ||
|
|
2bfb7c20c8 | ||
|
|
fb2178e5d3 | ||
|
|
4e2c4b0498 | ||
|
|
13d2f9131d | ||
|
|
64cdd509b0 | ||
|
|
bd15d2d0f7 | ||
|
|
64f5253bd3 | ||
|
|
9d0f3ce90b | ||
|
|
703faf3b15 | ||
|
|
5d8c79da38 | ||
|
|
522ddad72b | ||
|
|
11c4877859 | ||
|
|
2469032f15 | ||
|
|
bd9dc97b4f | ||
|
|
d6893f9d8a | ||
|
|
4f34bc0f0e | ||
|
|
a91e4d8a7f | ||
|
|
161c9b0fc7 | ||
|
|
0013a3b047 | ||
|
|
1889c256e1 | ||
|
|
9113932066 | ||
|
|
d3eaac8609 | ||
|
|
e6edf40048 | ||
|
|
dd38fed6e0 | ||
|
|
5ac656c638 | ||
|
|
6855ac1d5e | ||
|
|
29175d7ec4 | ||
|
|
92858e40bf | ||
|
|
e8b81db977 | ||
|
|
7420673a0f | ||
|
|
357a9179b1 | ||
|
|
2cefa9afca | ||
|
|
e1168f8de0 | ||
|
|
290cf8271b | ||
|
|
916182f80f | ||
|
|
2db9242f5c | ||
|
|
3c08e618bd | ||
|
|
c58fda0a70 | ||
|
|
b4c25bdc0a | ||
|
|
36a2c073bd | ||
|
|
776bec0d82 | ||
|
|
ab2dc60097 | ||
|
|
aee6bac5ef | ||
|
|
58b4c45d0c | ||
|
|
a6ce78a8c0 | ||
|
|
2ebf203412 | ||
|
|
45a03dd663 | ||
|
|
fcf720a5d8 | ||
|
|
cb1cdd1b23 | ||
|
|
0d92059155 | ||
|
|
80ab596992 | ||
|
|
b5f0190799 | ||
|
|
3d5a2046c4 | ||
|
|
341c3aded6 | ||
|
|
dd4dc19add | ||
|
|
1ab257d512 | ||
|
|
2ec8051303 | ||
|
|
ec30e6ace7 | ||
|
|
ced296939f | ||
|
|
1802f8a3f8 | ||
|
|
8b10315e2a | ||
|
|
e0fa4a6cb2 | ||
|
|
1366dd1fcd | ||
|
|
0850db2a9b | ||
|
|
a881e4e3f8 | ||
|
|
192a446131 | ||
|
|
b30c590866 | ||
|
|
6dd3ca31be | ||
|
|
c2e875d54b | ||
|
|
979f806161 | ||
|
|
3102a8d24b | ||
|
|
21d57b1f10 | ||
|
|
c873218c32 | ||
|
|
4c05287677 | ||
|
|
6713bc068b | ||
|
|
46d26cd029 | ||
|
|
88db5ec4d5 | ||
|
|
102d6e7a9a | ||
|
|
7add777b21 | ||
|
|
2db518c9c6 | ||
|
|
b91f6f0f5c | ||
|
|
115657a465 | ||
|
|
8e28e0a32b | ||
|
|
830ac1cc91 | ||
|
|
5206dafb35 | ||
|
|
c7a16a4bd5 | ||
|
|
707ff450b5 | ||
|
|
6a63279396 | ||
|
|
d3b3d07f2e | ||
|
|
a1fd9ea3ce | ||
|
|
db9d684524 | ||
|
|
15c621b1d8 | ||
|
|
cdf1c7a2a6 | ||
|
|
d265ed9729 | ||
|
|
18b3cc2683 | ||
|
|
c064eb0795 | ||
|
|
c2268c82ee | ||
|
|
caebdcfa91 | ||
|
|
6012f49919 | ||
|
|
d2f4a62bf3 | ||
|
|
9d25973a77 | ||
|
|
34fbe756e8 | ||
|
|
daad16ea93 | ||
|
|
6620f9263d | ||
|
|
9e40995ab0 | ||
|
|
ecdd95d15a | ||
|
|
d6b22f1f4c | ||
|
|
7ce7808093 | ||
|
|
2395075b7c | ||
|
|
bc24e3643f | ||
|
|
6d3f13076f | ||
|
|
905be1d894 | ||
|
|
a278e8b1e6 | ||
|
|
f0490a54b7 | ||
|
|
5ed1e1e5b6 | ||
|
|
df05efd7d9 | ||
|
|
7c12ade161 | ||
|
|
cb268075c2 | ||
|
|
9f5e8962b5 | ||
|
|
6525f25a22 | ||
|
|
aa15d2a7e2 | ||
|
|
1ca9912987 | ||
|
|
d43518cb3c | ||
|
|
cf64e2c97c | ||
|
|
3e00fe2b0f | ||
|
|
2ae5c0ec4f | ||
|
|
697f4aec95 | ||
|
|
023a1f222f | ||
|
|
a21e6448ce | ||
|
|
eb1b17b636 | ||
|
|
38cd3327f3 | ||
|
|
8ab358ccec | ||
|
|
641f7bbe9d | ||
|
|
a23fad0ba8 | ||
|
|
18277543b6 | ||
|
|
bfa0b87791 | ||
|
|
8c20f0c0d2 | ||
|
|
ee1ea47e88 | ||
|
|
82c4a4a03e | ||
|
|
21efe6f902 | ||
|
|
5c60dcd501 | ||
|
|
85e89c869a | ||
|
|
1485ff338f | ||
|
|
ac4b5ab7fa | ||
|
|
eb971a0320 | ||
|
|
92d9c41da7 | ||
|
|
ba91e3fc1f | ||
|
|
726ecd79e6 | ||
|
|
d22e276586 | ||
|
|
3d0319dba7 | ||
|
|
4a0efc0e86 | ||
|
|
445abf1e31 | ||
|
|
7f58552f60 | ||
|
|
2549085872 | ||
|
|
9e67a0b0e7 | ||
|
|
a1a232a1f1 | ||
|
|
c932213abd | ||
|
|
a0c19252df | ||
|
|
67c978b7a4 | ||
|
|
f4750f0096 | ||
|
|
676fec8694 | ||
|
|
60a0b66414 | ||
|
|
1050c9857a | ||
|
|
b21b03495d | ||
|
|
4632a7faba | ||
|
|
ccb39bea1a | ||
|
|
bda62cb1f1 | ||
|
|
09b76b306c | ||
|
|
e10f1274dc | ||
|
|
9468c16233 | ||
|
|
65fb0f901c | ||
|
|
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
|
||||
@@ -48,3 +49,6 @@ web/yarn-error.log
|
||||
/web/cacert.pem
|
||||
auditjs.html
|
||||
auditpy.txt
|
||||
/venv/
|
||||
.scannerwork/
|
||||
web/coverage/
|
||||
@@ -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 \
|
||||
@@ -45,12 +45,10 @@ RUN npm install && \
|
||||
npm audit fix && \
|
||||
rm -f yarn.lock && \
|
||||
yarn import && \
|
||||
# Commented the below line to avoid vulnerability in decompress package and
|
||||
# audit only dependencies folder. Refer https://www.npmjs.com/advisories/1217.
|
||||
# Pull request is already been send https://github.com/kevva/decompress/pull/73,
|
||||
# once fixed we will uncomment it.
|
||||
# Commented the below line to avoid vulnerability in lodash package.
|
||||
# Refer https://www.npmjs.com/advisories/1523.
|
||||
# Once fixed we will uncomment it.
|
||||
# yarn audit && \
|
||||
yarn audit --groups dependencies && \
|
||||
rm -f package-lock.json && \
|
||||
yarn run bundle && \
|
||||
rm -rf node_modules \
|
||||
@@ -66,7 +64,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 +96,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 +134,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/
|
||||
|
||||
@@ -154,6 +146,10 @@ COPY --from=app-builder /pgadmin4/web /pgadmin4
|
||||
COPY --from=docs-builder /pgadmin4/docs/en_US/_build/html/ /pgadmin4/docs
|
||||
COPY requirements.txt /pgadmin4/requirements.txt
|
||||
|
||||
# License files
|
||||
COPY LICENSE /pgadmin4/LICENSE
|
||||
COPY DEPENDENCIES /pgadmin4/DEPENDENCIES
|
||||
|
||||
# Install build-dependencies, build & install C extensions and purge deps in
|
||||
# one RUN step
|
||||
RUN apk add --no-cache --virtual \
|
||||
@@ -194,7 +190,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
|
||||
|
||||
@@ -2,23 +2,26 @@
|
||||
SETLOCAL
|
||||
|
||||
SET WD=%CD%
|
||||
SET "PGBUILDPATH=%WD%\win-build"
|
||||
SET "BUILDROOT=%WD%\win-build"
|
||||
SET "DISTROOT=%WD%\dist"
|
||||
|
||||
SET CMDOPTION=""
|
||||
IF "%1" == "clean" SET CMDOPTION="VALID"
|
||||
IF "%1" == "x86" SET CMDOPTION="VALID"
|
||||
SET CMDOPTIONS=""
|
||||
IF "%1" == "clean" SET CMDOPTIONS="VALID"
|
||||
IF "%1" == "" SET CMDOPTIONS="VALID"
|
||||
|
||||
IF NOT %CMDOPTION%=="VALID" (
|
||||
IF NOT %CMDOPTIONS%=="VALID" (
|
||||
GOTO USAGE
|
||||
)
|
||||
|
||||
SET ARCHITECTURE=%1
|
||||
|
||||
IF "%ARCHITECTURE%"=="clean" (
|
||||
IF "%1" == "clean" (
|
||||
CALL :CLEAN
|
||||
EXIT /B %ERRORLEVEL%
|
||||
)
|
||||
|
||||
set "ARCHITECTURE=x64"
|
||||
if "%Platform%" == "X86" (
|
||||
set "ARCHITECTURE=x86"
|
||||
)
|
||||
|
||||
REM Main build sequence
|
||||
CALL :SET_ENVIRONMENT
|
||||
@@ -37,7 +40,7 @@ REM Main build sequence Ends
|
||||
|
||||
:CLEAN
|
||||
ECHO Removing build directory...
|
||||
IF EXIST "%PGBUILDPATH%" RD "%PGBUILDPATH%" /S /Q > nul || EXIT /B 1
|
||||
IF EXIST "%BUILDROOT%" RD "%BUILDROOT%" /S /Q > nul || EXIT /B 1
|
||||
|
||||
ECHO Removing temp build directory...
|
||||
IF EXIST "%WD%\pkg\win32\Output" rd "%WD%\pkg\win32\Output" /S /Q > nul || EXIT /B 1
|
||||
@@ -50,40 +53,32 @@ REM Main build sequence Ends
|
||||
|
||||
:SET_ENVIRONMENT
|
||||
ECHO Configuring the environment...
|
||||
IF "%PYTHON_HOME%" == "" SET "PYTHON_HOME=C:\Python27"
|
||||
IF "%PYTHON_DLL%" == "" SET "PYTHON_DLL=C:\Windows\SysWOW64\python27.dll"
|
||||
IF "%QTDIR%" == "" SET "QTDIR=C:\Qt\5.9.1\mingw53_32"
|
||||
IF "%MAKE%" == "" SET "MAKE=mingw32-make.exe"
|
||||
IF "%PGDIR%" == "" SET "PGDIR=C:\Program Files (x86)\PostgreSQL\10"
|
||||
IF "%INNOTOOL%" == "" SET "INNOTOOL=C:\Program Files (x86)\Inno Setup 5"
|
||||
IF "%VCREDIST%" == "" SET "VCREDIST=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\1033\vcredist_x86.exe"
|
||||
IF "%SIGNTOOL%" == "" SET "SIGNTOOL=C:\Program Files\Microsoft SDKs\Windows\v7.1A\Bin\signtool.exe"
|
||||
IF "%PGADMIN_PYTHON_DIR%" == "" SET "PGADMIN_PYTHON_DIR=C:\Python38"
|
||||
IF "%PGADMIN_QT_DIR%" == "" SET "PGADMIN_QT_DIR=C:\Qt\5.14.2\msvc2017_64"
|
||||
IF "%PGADMIN_POSTGRES_DIR%" == "" SET "PGADMIN_POSTGRES_DIR=C:\Program Files (x86)\PostgreSQL\12"
|
||||
IF "%PGADMIN_INNOTOOL_DIR%" == "" SET "PGADMIN_INNOTOOL_DIR=C:\Program Files (x86)\Inno Setup 6"
|
||||
IF "%PGADMIN_VCREDIST_DIR%" == "" SET "PGADMIN_VCREDIST_DIR=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Redist\MSVC\14.16.27012"
|
||||
IF "%PGADMIN_SIGNTOOL_DIR%" == "" SET "PGADMIN_SIGNTOOL_DIR=C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64"
|
||||
|
||||
REM Set VCREDISTNAME (the filename)
|
||||
for /f "delims=" %%i in ("%VCREDIST%") do set "VCREDISTNAME=%%~nxi"
|
||||
REM Set REDIST_NAME (the filename)
|
||||
set "VCREDIST_FILE=vcredist_%ARCHITECTURE%.exe"
|
||||
|
||||
REM Set additional variables we need
|
||||
SET "QMAKE=%QTDIR%\bin\qmake.exe"
|
||||
FOR /F "tokens=4,5 delims=. " %%a IN ('%QMAKE% -v ^| findstr /B /C:"Using Qt version "') DO SET QT_VERSION=%%a.%%b
|
||||
|
||||
SET "VIRTUALENV=venv"
|
||||
SET "TARGET_DIR=%WD%\dist"
|
||||
|
||||
FOR /F "tokens=3" %%a IN ('findstr /C:"APP_RELEASE =" %WD%\web\config.py') DO SET APP_MAJOR=%%a
|
||||
FOR /F "tokens=3" %%a IN ('findstr /C:"APP_REVISION =" %WD%\web\config.py') DO SET APP_MINOR=%%a
|
||||
FOR /F "tokens=3" %%a IN ('findstr /C:"APP_SUFFIX =" %WD%\web\config.py') DO SET APP_VERSION_SUFFIX=%%a
|
||||
FOR /F "tokens=3" %%a IN ('findstr /C:"APP_RELEASE =" %WD%\web\config.py') DO SET APP_MAJOR=%%a
|
||||
FOR /F "tokens=3" %%a IN ('findstr /C:"APP_REVISION =" %WD%\web\config.py') DO SET APP_MINOR=%%a
|
||||
FOR /F "tokens=3" %%a IN ('findstr /C:"APP_SUFFIX =" %WD%\web\config.py') DO SET APP_VERSION_SUFFIX=%%a
|
||||
REM remove single quote from the string
|
||||
SET APP_VERSION_SUFFIX=%APP_VERSION_SUFFIX:'=%
|
||||
SET APP_NAME=""
|
||||
FOR /F "tokens=2* DELims='" %%a IN ('findstr /C:"APP_NAME =" web\config.py') DO SET APP_NAME=%%a
|
||||
FOR /f "tokens=1 DELims=." %%G IN ('%PYTHON_HOME%/python.exe -c "print('%APP_NAME%'.lower().replace(' ', ''))"') DO SET APP_SHORTNAME=%%G
|
||||
FOR /F "tokens=2* DELims='" %%a IN ('findstr /C:"APP_NAME =" web\config.py') DO SET APP_NAME=%%a
|
||||
FOR /f "tokens=1 DELims=." %%G IN ('%PGADMIN_PYTHON_DIR%/python.exe -c "print('%APP_NAME%'.lower().replace(' ', ''))"') DO SET APP_SHORTNAME=%%G
|
||||
SET APP_VERSION=%APP_MAJOR%.%APP_MINOR%
|
||||
SET INSTALLERNAME=%APP_SHORTNAME%-%APP_MAJOR%.%APP_MINOR%-%APP_VERSION_SUFFIX%-%ARCHITECTURE%.exe
|
||||
IF "%APP_VERSION_SUFFIX%" == "" SET INSTALLERNAME=%APP_SHORTNAME%-%APP_MAJOR%.%APP_MINOR%-%ARCHITECTURE%.exe
|
||||
|
||||
REM get Python version for the runtime build ex. 2.7.1 will be 27
|
||||
FOR /f "tokens=1 DELims=." %%G IN ('%PYTHON_HOME%/python.exe -c "import sys; print(sys.version.split(' ')[0])"') DO SET PYTHON_MAJOR=%%G
|
||||
FOR /f "tokens=2 DELims=." %%G IN ('%PYTHON_HOME%/python.exe -c "import sys; print(sys.version.split(' ')[0])"') DO SET PYTHON_MINOR=%%G
|
||||
FOR /f "tokens=1 DELims=." %%G IN ('%PGADMIN_PYTHON_DIR%/python.exe -c "import sys; print(sys.version.split(' ')[0])"') DO SET PYTHON_MAJOR=%%G
|
||||
FOR /f "tokens=2 DELims=." %%G IN ('%PGADMIN_PYTHON_DIR%/python.exe -c "import sys; print(sys.version.split(' ')[0])"') DO SET PYTHON_MINOR=%%G
|
||||
SET "PYTHON_VERSION=%PYTHON_MAJOR%%PYTHON_MINOR%"
|
||||
|
||||
EXIT /B 0
|
||||
@@ -91,32 +86,24 @@ REM Main build sequence Ends
|
||||
|
||||
:VALIDATE_ENVIRONMENT
|
||||
ECHO ****************************************************************
|
||||
ECHO S U M M A R Y
|
||||
ECHO * Build summary
|
||||
ECHO ****************************************************************
|
||||
ECHO Build path: %PGBUILDPATH%
|
||||
ECHO Output directory: %TARGET_DIR%
|
||||
ECHO Build path: %BUILDROOT%
|
||||
ECHO Output directory: %DISTROOT%
|
||||
ECHO Installer name: %INSTALLERNAME%
|
||||
ECHO.
|
||||
ECHO Python home: %PYTHON_HOME%
|
||||
ECHO Python DLL: %PYTHON_DLL%
|
||||
ECHO Python version: %PYTHON_VERSION%
|
||||
ECHO Python major version: %PYTHON_MAJOR%
|
||||
ECHO Python minor version: %PYTHON_MINOR%
|
||||
ECHO Python directory: %PGADMIN_PYTHON_DIR%
|
||||
ECHO Python DLL: %PGADMIN_PYTHON_DIR%\Python%PYTHON_VERSION%.dll
|
||||
ECHO Python version: %PYTHON_MAJOR%.%PYTHON_MINOR%
|
||||
ECHO.
|
||||
ECHO Qt home: %QTDIR%
|
||||
ECHO qmake executable: %QMAKE%
|
||||
ECHO Qt version: %QT_VERSION%
|
||||
ECHO Qt directory: %PGADMIN_QT_DIR%
|
||||
ECHO PostgreSQL directory: %PGADMIN_POSTGRES_DIR%
|
||||
ECHO.
|
||||
ECHO PostgreSQL home: %PGDIR%
|
||||
ECHO VC++ redist directory: %PGADMIN_VCREDIST_DIR%
|
||||
ECHO VC++ redist file: %VCREDIST_FILE%
|
||||
ECHO InnoTool directory: %PGADMIN_INNOTOOL_DIR%
|
||||
ECHO signtool directory: %PGADMIN_SIGNTOOL_DIR%
|
||||
ECHO.
|
||||
ECHO VC++ redistributable: %VCREDIST%
|
||||
ECHO VC++ redistributable file: %VCREDISTNAME%
|
||||
ECHO.
|
||||
ECHO innotool executable: %INNOTOOL%
|
||||
ECHO signtool executable: %SIGNTOOL%
|
||||
ECHO.
|
||||
ECHO App major version: %APP_MAJOR%
|
||||
ECHO App minor version: %APP_MINOR%
|
||||
ECHO App version: %APP_VERSION%
|
||||
ECHO App version suffix: %APP_VERSION_SUFFIX%
|
||||
ECHO App short name: %APP_SHORTNAME%
|
||||
@@ -124,88 +111,87 @@ REM Main build sequence Ends
|
||||
ECHO ****************************************************************
|
||||
|
||||
ECHO Checking the environment...
|
||||
IF NOT EXIST "%INNOTOOL%" (
|
||||
ECHO !INNOTOOL! does not exist
|
||||
ECHO Please install Innotool and set the INNOTOOL environment variable.
|
||||
IF NOT EXIST "%PGADMIN_INNOTOOL_DIR%" (
|
||||
ECHO !PGADMIN_INNOTOOL_DIR! does not exist
|
||||
ECHO Please install InnoTool and set the PGADMIN_INNOTOOL_DIR environment variable.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%VCREDIST%" (
|
||||
ECHO !VCREDIST! does not exist
|
||||
ECHO Please install Microsoft Visual studio and set the VCREDIST environment variable.
|
||||
IF NOT EXIST "%PGADMIN_VCREDIST_DIR%" (
|
||||
ECHO !PGADMIN_VCREDIST_DIR! does not exist
|
||||
ECHO Please install Microsoft Visual studio and set the PGADMIN_VCREDIST_DIR environment variable.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%QTDIR%" (
|
||||
ECHO !QTDIR! does not exist.
|
||||
ECHO Please install Qt and set the QTDIR environment variable.
|
||||
IF NOT EXIST "%PGADMIN_QT_DIR%" (
|
||||
ECHO !PGADMIN_QT_DIR! does not exist.
|
||||
ECHO Please install Qt and set the PGADMIN_QT_DIR environment variable.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%QMAKE%" (
|
||||
IF NOT EXIST "%PGADMIN_QT_DIR%\bin\qmake.exe" (
|
||||
ECHO !QMAKE! does not exist.
|
||||
ECHO Please install Qt and set the QTDIR environment variable.
|
||||
ECHO Please install Qt and set the PGADMIN_QT_DIR environment variable.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%PYTHON_HOME%" (
|
||||
ECHO !PYTHON_HOME! does not exist.
|
||||
ECHO Please install Python and set the PYTHON_HOME environment variable.
|
||||
IF NOT EXIST "%PGADMIN_PYTHON_DIR%" (
|
||||
ECHO !PGADMIN_PYTHON_DIR! does not exist.
|
||||
ECHO Please install Python and set the PGADMIN_PYTHON_DIR environment variable.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%PYTHON_DLL%" (
|
||||
ECHO !PYTHON_DLL! does not exist.
|
||||
ECHO Please install Python and set the PYTHON_DLL environment variable.
|
||||
IF NOT EXIST "%PGADMIN_PYTHON_DIR%\Python%PYTHON_VERSION%.dll" (
|
||||
ECHO !PGADMIN_PYTHON_DIR!\Python!PYTHON_VERSION!.dll does not exist.
|
||||
ECHO Please check your Python installation is complete.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%PGDIR%" (
|
||||
ECHO !PGDIR! does not exist.
|
||||
ECHO Please install PostgreSQL and set the PGDIR environment variable.
|
||||
IF NOT EXIST "%PGADMIN_POSTGRES_DIR%" (
|
||||
ECHO !PGADMIN_POSTGRES_DIR! does not exist.
|
||||
ECHO Please install PostgreSQL and set the PGADMIN_POSTGRES_DIR environment variable.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
IF NOT EXIST "%PYTHON_HOME%\Scripts\virtualenv.exe" (
|
||||
ECHO !PYTHON_HOME!\Scripts\virtualenv.exe does not exist.
|
||||
IF NOT EXIST "%PGADMIN_PYTHON_DIR%\Scripts\virtualenv.exe" (
|
||||
ECHO !PGADMIN_PYTHON_DIR!\Scripts\virtualenv.exe does not exist.
|
||||
ECHO Please install the virtualenv package in Python.
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
SET "PATH=%PGDIR%\bin;%PATH%"
|
||||
SET "PATH=%PGADMIN_POSTGRES_DIR%\bin;%PATH%"
|
||||
|
||||
EXIT /B 0
|
||||
|
||||
|
||||
:CREATE_VIRTUAL_ENV
|
||||
ECHO Creating virtual environment...
|
||||
IF NOT EXIST "%PGBUILDPATH%" MKDIR "%PGBUILDPATH%"
|
||||
IF NOT EXIST "%BUILDROOT%" MKDIR "%BUILDROOT%"
|
||||
|
||||
CD "%PGBUILDPATH%"
|
||||
"%PYTHON_HOME%\Scripts\virtualenv.exe" "%VIRTUALENV%"
|
||||
CD "%BUILDROOT%"
|
||||
|
||||
XCOPY /S /I /E /H /Y "%PYTHON_HOME%\DLLs" "%PGBUILDPATH%\%VIRTUALENV%\DLLs" > nul || EXIT /B 1
|
||||
XCOPY /S /I /E /H /Y "%PYTHON_HOME%\Lib" "%PGBUILDPATH%\%VIRTUALENV%\Lib" > nul || EXIT /B 1
|
||||
REM Note that we must use virtualenv.exe here, as the venv module doesn't allow python.exe to relocate.
|
||||
"%PGADMIN_PYTHON_DIR%\Scripts\virtualenv.exe" venv
|
||||
|
||||
ECHO Activating virtual environment - %PGBUILDPATH%\%VIRTUALENV%...
|
||||
CALL "%PGBUILDPATH%\%VIRTUALENV%\Scripts\activate" || EXIT /B 1
|
||||
XCOPY /S /I /E /H /Y "%PGADMIN_PYTHON_DIR%\DLLs" "%BUILDROOT%\venv\DLLs" > nul || EXIT /B 1
|
||||
XCOPY /S /I /E /H /Y "%PGADMIN_PYTHON_DIR%\Lib" "%BUILDROOT%\venv\Lib" > nul || EXIT /B 1
|
||||
|
||||
ECHO Activating virtual environment - %BUILDROOT%\venv...
|
||||
CALL "%BUILDROOT%\venv\Scripts\activate" || EXIT /B 1
|
||||
|
||||
ECHO Installing dependencies...
|
||||
CALL pip install -r "%WD%\requirements.txt" || EXIT /B 1
|
||||
CALL pip install sphinx || EXIT /B 1
|
||||
|
||||
REM If we're using VC++, and this is Python 3.6+, we need to remove the hack
|
||||
REM above or it will break qmake. Sigh.
|
||||
IF "%MAKE%" == "nmake" (
|
||||
IF %PYTHON_VERSION% GEQ 36 SET CL=
|
||||
)
|
||||
REM If this is Python 3.6+, we need to remove the hack above or it will break qmake. Sigh.
|
||||
IF %PYTHON_VERSION% GEQ 36 SET CL=
|
||||
|
||||
CD %WD%
|
||||
EXIT /B 0
|
||||
|
||||
|
||||
:CREATE_RUNTIME_ENV
|
||||
MKDIR "%PGBUILDPATH%\runtime"
|
||||
MKDIR "%BUILDROOT%\runtime"
|
||||
|
||||
CD "%WD%\web"
|
||||
|
||||
@@ -219,33 +205,37 @@ REM Main build sequence Ends
|
||||
RD /Q /S "%WD%\web\pgadmin\static\js\generated\.cache" 1> nul 2>&1
|
||||
|
||||
ECHO Copying web directory...
|
||||
XCOPY /S /I /E /H /Y "%WD%\web" "%PGBUILDPATH%\web" > nul || EXIT /B 1
|
||||
XCOPY /S /I /E /H /Y "%WD%\web" "%BUILDROOT%\web" > nul || EXIT /B 1
|
||||
|
||||
ECHO Cleaning up unnecessary .pyc and .pyo files...
|
||||
FOR /R "%PGBUILDPATH%\web" %%f in (*.pyc *.pyo) do DEL /q "%%f" 1> nul 2>&1
|
||||
FOR /R "%BUILDROOT%\web" %%f in (*.pyc *.pyo) do DEL /q "%%f" 1> nul 2>&1
|
||||
ECHO Removing tests, Python caches and node modules...
|
||||
FOR /R "%PGBUILDPATH%\web" %%f in (tests feature_tests __pycache__ node_modules) do RD /Q /S "%%f" 1> nul 2>&1
|
||||
FOR /R "%BUILDROOT%\web" %%f in (tests feature_tests __pycache__ node_modules) do RD /Q /S "%%f" 1> nul 2>&1
|
||||
ECHO Removing the test framework...
|
||||
RD /Q /S "%PGBUILDPATH%\web\regression" 1> nul 2>&1
|
||||
RD /Q /S "%BUILDROOT%\web\regression" 1> nul 2>&1
|
||||
ECHO Removing tools...
|
||||
RD /Q /S "%PGBUILDPATH%\web\tools" 1> nul 2>&1
|
||||
RD /Q /S "%BUILDROOT%\web\tools" 1> nul 2>&1
|
||||
ECHO Removing any existing configurations...
|
||||
DEL /q "%PGBUILDPATH%\web\pgadmin4.db" 1> nul 2>&1
|
||||
DEL /q "%PGBUILDPATH%\web\config_local.py" 1> nul 2>&1
|
||||
|
||||
DEL /q "%BUILDROOT%\web\pgadmin4.db" 1> nul 2>&1
|
||||
DEL /q "%BUILDROOT%\web\config_local.py" 1> nul 2>&1
|
||||
|
||||
ECHO Staging license files...
|
||||
COPY "%WD%\LICENSE" "%BUILDROOT%\" > nul || EXIT /B 1
|
||||
COPY "%WD%\DEPENDENCIES" "%BUILDROOT%\" > nul || EXIT /B 1
|
||||
|
||||
ECHO Creating config_distro.py
|
||||
ECHO SERVER_MODE = False > "%PGBUILDPATH%\web\config_distro.py"
|
||||
ECHO HELP_PATH = '../../../docs/en_US/html/' >> "%PGBUILDPATH%\web\config_distro.py"
|
||||
ECHO DEFAULT_BINARY_PATHS = { >> "%PGBUILDPATH%\web\config_distro.py"
|
||||
ECHO 'pg': '$DIR/../runtime', >> "%PGBUILDPATH%\web\config_distro.py"
|
||||
ECHO 'ppas': '' >> "%PGBUILDPATH%\web\config_distro.py"
|
||||
ECHO } >> "%PGBUILDPATH%\web\config_distro.py"
|
||||
ECHO SERVER_MODE = False > "%BUILDROOT%\web\config_distro.py"
|
||||
ECHO HELP_PATH = '../../../docs/en_US/html/' >> "%BUILDROOT%\web\config_distro.py"
|
||||
ECHO DEFAULT_BINARY_PATHS = { >> "%BUILDROOT%\web\config_distro.py"
|
||||
ECHO 'pg': '$DIR/../runtime', >> "%BUILDROOT%\web\config_distro.py"
|
||||
ECHO 'ppas': '' >> "%BUILDROOT%\web\config_distro.py"
|
||||
ECHO } >> "%BUILDROOT%\web\config_distro.py"
|
||||
|
||||
ECHO Building docs...
|
||||
MKDIR "%PGBUILDPATH%\docs\en_US\html"
|
||||
MKDIR "%BUILDROOT%\docs\en_US\html"
|
||||
CD "%WD%\docs\en_US"
|
||||
CALL "%PGBUILDPATH%\%VIRTUALENV%\Scripts\python.exe" build_code_snippet.py || EXIT /B 1
|
||||
CALL "%PGBUILDPATH%\%VIRTUALENV%\Scripts\sphinx-build.exe" "%WD%\docs\en_US" "%PGBUILDPATH%\docs\en_US\html" || EXIT /B 1
|
||||
CALL "%BUILDROOT%\venv\Scripts\python.exe" build_code_snippet.py || EXIT /B 1
|
||||
CALL "%BUILDROOT%\venv\Scripts\sphinx-build.exe" "%WD%\docs\en_US" "%BUILDROOT%\docs\en_US\html" || EXIT /B 1
|
||||
|
||||
ECHO Removing Sphinx
|
||||
CALL pip uninstall -y sphinx Pygments alabaster colorama docutils imagesize requests snowballstemmer
|
||||
@@ -254,56 +244,50 @@ REM Main build sequence Ends
|
||||
CD "%WD%\runtime"
|
||||
|
||||
ECHO Running qmake...
|
||||
CALL "%QMAKE%" || EXIT /B 1
|
||||
CALL set "PGADMIN_PYTHON_DIR=%PGADMIN_PYTHON_DIR%" && "%PGADMIN_QT_DIR%\bin\qmake.exe" || EXIT /B 1
|
||||
|
||||
ECHO Cleaning the build directory...
|
||||
CALL %MAKE% clean || EXIT /B 1
|
||||
CALL nmake clean || EXIT /B 1
|
||||
|
||||
ECHO Running make...
|
||||
CALL %MAKE% || EXIT /B 1
|
||||
CALL nmake || EXIT /B 1
|
||||
|
||||
ECHO Staging pgAdmin4.exe...
|
||||
COPY "%WD%\runtime\release\pgAdmin4.exe" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%WD%\runtime\release\pgAdmin4.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
|
||||
ECHO Staging Qt components...
|
||||
COPY "%QTDIR%\bin\Qt5Core.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%QTDIR%\bin\Qt5Gui.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%QTDIR%\bin\Qt5Widgets.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%QTDIR%\bin\Qt5Network.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%QTDIR%\bin\Qt5Svg.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%QTDIR%\bin\libgcc_s_dw2-1.dll" COPY "%QTDIR%\bin\libgcc_s_dw2-1.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%QTDIR%\bin\libstdc++-6.dll" COPY "%QTDIR%\bin\libstdc++-6.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%QTDIR%\bin\libwinpthread-1.dll" COPY "%QTDIR%\bin\libwinpthread-1.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
MKDIR "%PGBUILDPATH%\runtime\platforms" > nul || EXIT /B 1
|
||||
COPY "%QTDIR%\plugins\platforms\qwindows.dll" "%PGBUILDPATH%\runtime\platforms" > nul || EXIT /B 1
|
||||
MKDIR "%PGBUILDPATH%\runtime\imageformats" > nul || EXIT /B 1
|
||||
COPY "%QTDIR%\plugins\imageformats\qsvg.dll" "%PGBUILDPATH%\runtime\imageformats" > nul || EXIT /B 1
|
||||
ECHO [Paths] > "%PGBUILDPATH%\runtime\qt.conf"
|
||||
ECHO Plugins=plugins >> "%PGBUILDPATH%\runtime\qt.conf"
|
||||
COPY "%PGADMIN_QT_DIR%\bin\Qt5Core.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_QT_DIR%\bin\Qt5Gui.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_QT_DIR%\bin\Qt5Widgets.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_QT_DIR%\bin\Qt5Network.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_QT_DIR%\bin\Qt5Svg.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
MKDIR "%BUILDROOT%\runtime\platforms" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_QT_DIR%\plugins\platforms\qwindows.dll" "%BUILDROOT%\runtime\platforms" > nul || EXIT /B 1
|
||||
MKDIR "%BUILDROOT%\runtime\imageformats" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_QT_DIR%\plugins\imageformats\qsvg.dll" "%BUILDROOT%\runtime\imageformats" > nul || EXIT /B 1
|
||||
ECHO [Paths] > "%BUILDROOT%\runtime\qt.conf"
|
||||
ECHO Plugins=plugins >> "%BUILDROOT%\runtime\qt.conf"
|
||||
|
||||
ECHO Staging PostgreSQL components...
|
||||
COPY "%PGDIR%\bin\libpq.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%PGDIR%\bin\libcrypto-1_1.dll" (
|
||||
REM OpenSSL 1.1.1
|
||||
COPY "%PGDIR%\bin\libcrypto-1_1.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGDIR%\bin\libssl-1_1.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libpq.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
IF "%ARCHITECTURE%" == "x64" (
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libcrypto-1_1-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libssl-1_1-x64.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
) ELSE (
|
||||
REM OpenSSL 1.0.2
|
||||
COPY "%PGDIR%\bin\ssleay32.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGDIR%\bin\libeay32.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libcrypto-1_1.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\libssl-1_1.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
)
|
||||
IF EXIST "%PGDIR%\bin\libintl-*.dll" COPY "%PGDIR%\bin\libintl-*.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%PGDIR%\bin\libiconv-*.dll" COPY "%PGDIR%\bin\libiconv-*.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%PGDIR%\bin\zlib.dll" COPY "%PGDIR%\bin\zlib.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%PGDIR%\bin\zlib1.dll" COPY "%PGDIR%\bin\zlib1.dll" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGDIR%\bin\pg_dump.exe" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGDIR%\bin\pg_dumpall.exe" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1L%
|
||||
COPY "%PGDIR%\bin\pg_restore.exe" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGDIR%\bin\psql.exe" "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
IF EXIST "%PGADMIN_POSTGRES_DIR%\bin\libintl-*.dll" COPY "%PGADMIN_POSTGRES_DIR%\bin\libintl-*.dll" "%BUILDROOT%\runtime" > nul
|
||||
IF EXIST "%PGADMIN_POSTGRES_DIR%\bin\libiconv-*.dll" COPY "%PGADMIN_POSTGRES_DIR%\bin\libiconv-*.dll" "%BUILDROOT%\runtime" > nul
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\zlib.dll" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\pg_dump.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\pg_dumpall.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1L%
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\pg_restore.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY "%PGADMIN_POSTGRES_DIR%\bin\psql.exe" "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
|
||||
ECHO Staging VC++ runtime...
|
||||
MKDIR "%PGBUILDPATH%\installer" || EXIT /B 1
|
||||
COPY "%VCREDIST%" "%PGBUILDPATH%\installer" > nul || EXIT /B 1
|
||||
MKDIR "%BUILDROOT%\installer" || EXIT /B 1
|
||||
COPY "%PGADMIN_VCREDIST_DIR%\%VCREDIST_FILE%" "%BUILDROOT%\installer" > nul || EXIT /B 1
|
||||
|
||||
CD %WD%
|
||||
EXIT /B 0
|
||||
@@ -311,51 +295,51 @@ REM Main build sequence Ends
|
||||
|
||||
:CREATE_PYTHON_ENV
|
||||
ECHO Staging Python...
|
||||
COPY %PYTHON_DLL% "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY %PYTHON_HOME%\python.exe "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY %PYTHON_HOME%\pythonw.exe "%PGBUILDPATH%\runtime" > nul || EXIT /B 1
|
||||
COPY %PGADMIN_PYTHON_DIR%\python%PYTHON_VERSION%.dll "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY %PGADMIN_PYTHON_DIR%\python.exe "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
COPY %PGADMIN_PYTHON_DIR%\pythonw.exe "%BUILDROOT%\runtime" > nul || EXIT /B 1
|
||||
|
||||
ECHO Cleaning up unnecessary .pyc and .pyo files...
|
||||
FOR /R "%PGBUILDPATH%\%VIRTUALENV%" %%f in (*.pyc *.pyo) do DEL /q "%%f" 1> nul 2>&1
|
||||
FOR /R "%BUILDROOT%\venv" %%f in (*.pyc *.pyo) do DEL /q "%%f" 1> nul 2>&1
|
||||
ECHO Removing tests...
|
||||
FOR /R "%PGBUILDPATH%\%VIRTUALENV%\Lib" %%f in (test tests) do RD /Q /S "%%f" 1> nul 2>&1
|
||||
FOR /R "%BUILDROOT%\venv\Lib" %%f in (test tests) do RD /Q /S "%%f" 1> nul 2>&1
|
||||
ECHO Removing TCL...
|
||||
RD /Q /S "%PGBUILDPATH%\%VIRTUALENV%\tcl" 1> nul 2>&1
|
||||
RD /Q /S "%BUILDROOT%\venv\tcl" 1> nul 2>&1
|
||||
|
||||
EXIT /B 0
|
||||
|
||||
|
||||
:CREATE_INSTALLER
|
||||
ECHO Preparing for creation of windows installer...
|
||||
IF NOT EXIST "%TARGET_DIR%" MKDIR "%TARGET_DIR%"
|
||||
IF NOT EXIST "%DISTROOT%" MKDIR "%DISTROOT%"
|
||||
|
||||
ECHO Copying icon file...
|
||||
COPY "%WD%\pkg\win32\Resources\pgAdmin4.ico" "%PGBUILDPATH%" > nul || EXIT /B 1
|
||||
COPY "%WD%\pkg\win32\Resources\pgAdmin4.ico" "%BUILDROOT%" > nul || EXIT /B 1
|
||||
|
||||
CD "%WD%\pkg\win32"
|
||||
|
||||
ECHO Processing installer configuration script...
|
||||
CALL "%PYTHON_HOME%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in" "-o" "%WD%\pkg\win32\installer.iss.in_stage1" "-s" MYAPP_NAME -r """%APP_NAME%"""
|
||||
CALL "%PYTHON_HOME%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage1" "-o" "%WD%\pkg\win32\installer.iss.in_stage2" "-s" MYAPP_FULLVERSION -r """%APP_VERSION%"""
|
||||
CALL "%PYTHON_HOME%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage2" "-o" "%WD%\pkg\win32\installer.iss.in_stage3" "-s" MYAPP_VERSION -r """v%APP_MAJOR%"""
|
||||
CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in" "-o" "%WD%\pkg\win32\installer.iss.in_stage1" "-s" MYAPP_NAME -r """%APP_NAME%"""
|
||||
CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage1" "-o" "%WD%\pkg\win32\installer.iss.in_stage2" "-s" MYAPP_FULLVERSION -r """%APP_VERSION%"""
|
||||
CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage2" "-o" "%WD%\pkg\win32\installer.iss.in_stage3" "-s" MYAPP_VERSION -r """v%APP_MAJOR%"""
|
||||
|
||||
SET ARCMODE=
|
||||
IF "%ARCHITECTURE%"=="amd64" (
|
||||
IF "%ARCHITECTURE%" == "x64" (
|
||||
set ARCMODE="x64"
|
||||
)
|
||||
CALL "%PYTHON_HOME%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage3" "-o" "%WD%\pkg\win32\installer.iss.in_stage4" "-s" MYAPP_ARCHITECTURESMODE -r """%ARCMODE%"""
|
||||
CALL "%PYTHON_HOME%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage4" "-o" "%WD%\pkg\win32\installer.iss" "-s" MYAPP_VCDIST -r """%VCREDISTNAME%"""
|
||||
CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage3" "-o" "%WD%\pkg\win32\installer.iss.in_stage4" "-s" MYAPP_ARCHITECTURESMODE -r """%ARCMODE%"""
|
||||
CALL "%PGADMIN_PYTHON_DIR%\python" "%WD%\pkg\win32\replace.py" "-i" "%WD%\pkg\win32\installer.iss.in_stage4" "-o" "%WD%\pkg\win32\installer.iss" "-s" MYAPP_VCDIST -r """%PGADMIN_VCREDIST_DIRNAME%\%VCREDIST_FILE%"""
|
||||
|
||||
ECHO Cleaning up...
|
||||
DEL /s "%WD%\pkg\win32\installer.iss.in_stage*" > nul
|
||||
|
||||
ECHO Creating windows installer using INNO tool...
|
||||
CALL "%INNOTOOL%\ISCC.exe" /q "%WD%\pkg\win32\installer.iss" || EXIT /B 1
|
||||
CALL "%PGADMIN_INNOTOOL_DIR%\ISCC.exe" /q "%WD%\pkg\win32\installer.iss" || EXIT /B 1
|
||||
|
||||
ECHO Renaming installer...
|
||||
MOVE "%WD%\pkg\win32\Output\Setup.exe" "%TARGET_DIR%\%INSTALLERNAME%" > nul || EXIT /B 1
|
||||
MOVE "%WD%\pkg\win32\Output\Setup.exe" "%DISTROOT%\%INSTALLERNAME%" > nul || EXIT /B 1
|
||||
|
||||
ECHO Location - %TARGET_DIR%\%INSTALLERNAME%
|
||||
ECHO Location - %DISTROOT%\%INSTALLERNAME%
|
||||
ECHO Installer generated successfully.
|
||||
|
||||
CD %WD%
|
||||
@@ -364,7 +348,7 @@ REM Main build sequence Ends
|
||||
|
||||
:SIGN_INSTALLER
|
||||
ECHO Attempting to sign the installer...
|
||||
CALL "%SIGNTOOL%" sign /t http://timestamp.verisign.com/scripts/timstamp.dll "%TARGET_DIR%\%INSTALLERNAME%"
|
||||
CALL "%PGADMIN_SIGNTOOL_DIR%\signtool.exe" sign /t http://timestamp.verisign.com/scripts/timstamp.dll "%DISTROOT%\%INSTALLERNAME%"
|
||||
IF %ERRORLEVEL% NEQ 0 (
|
||||
ECHO.
|
||||
ECHO ************************************************************
|
||||
@@ -378,15 +362,15 @@ REM Main build sequence Ends
|
||||
|
||||
:CLEANUP_ENV
|
||||
ECHO Cleaning the build environment...
|
||||
RD "%PGBUILDPATH%\%VIRTUALENV%\Include" /S /Q 1> nul 2>&1
|
||||
DEL /s "%PGBUILDPATH%\%VIRTUALENV%\pip-selfcheck.json" 1> nul 2>&1
|
||||
RD "%BUILDROOT%\venv\Include" /S /Q 1> nul 2>&1
|
||||
DEL /s "%BUILDROOT%\venv\pip-selfcheck.json" 1> nul 2>&1
|
||||
|
||||
EXIT /B 0
|
||||
|
||||
|
||||
:USAGE
|
||||
ECHO Invalid command line options.
|
||||
ECHO Usage: "Make.bat <x86 | clean>"
|
||||
ECHO Usage: "Make.bat [clean]"
|
||||
ECHO.
|
||||
|
||||
EXIT /B 1
|
||||
|
||||
@@ -28,12 +28,10 @@ install-node:
|
||||
cd web && npm audit fix
|
||||
rm -f web/yarn.lock
|
||||
cd web && yarn import
|
||||
# Commented the below line to avoid vulnerability in decompress package and
|
||||
# audit only dependencies folder. Refer https://www.npmjs.com/advisories/1217.
|
||||
# Pull request is already been send https://github.com/kevva/decompress/pull/73,
|
||||
# once fixed we will uncomment it.
|
||||
# Commented the below line to avoid vulnerability in lodash package.
|
||||
# Refer https://www.npmjs.com/advisories/1523.
|
||||
# Once fixed we will uncomment it.
|
||||
# cd web && yarn audit
|
||||
cd web && yarn audit --groups dependencies
|
||||
rm -f package-lock.json
|
||||
rm -f web/package-lock.json
|
||||
|
||||
@@ -84,6 +82,9 @@ check-feature: install-node bundle
|
||||
check-js: install-node linter
|
||||
cd web && yarn run karma start --single-run
|
||||
|
||||
check-js-coverage:
|
||||
cd web && yarn run test:karma-coverage
|
||||
|
||||
runtime-debug:
|
||||
cd runtime && qmake CONFIG+=debug && make
|
||||
|
||||
|
||||
@@ -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,16 +185,7 @@ 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:
|
||||
|
||||
https://www.microsoft.com/en-gb/download/details.aspx?id=44266
|
||||
|
||||
A blog detailing the setup of Virtual Environments on Windows can be found
|
||||
here:
|
||||
|
||||
http://www.tylerbutler.com/2012/05/how-to-install-python-pip-and-virtualenv-on-windows-with-powershell/
|
||||
please see pkg/win32/README.txt for complete details.
|
||||
|
||||
Once a virtual environment has been created and enabled, setup can continue
|
||||
from step 4 above.
|
||||
@@ -252,7 +247,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,49 +289,9 @@ run:
|
||||
|
||||
(pgadmin4) $ make pip
|
||||
|
||||
On a Mac, build an application bundle in a disk image (DMG file) with:
|
||||
To build the macOS AppBundle, please see pkg/mac/README.
|
||||
|
||||
(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.
|
||||
|
||||
On Windows, the InnoSetup tool is required to create an installer. Download the
|
||||
Unicode version from:
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
To build the installer:
|
||||
|
||||
C:\$PGADMIN4_SRC> make x86
|
||||
|
||||
If you have a code signing certificate, this will automatically be used if
|
||||
found in the Windows Certificate Store to sign the installer.
|
||||
To build the Windows installer, please see pkg/win32/README.txt.
|
||||
|
||||
Support
|
||||
-------
|
||||
|
||||
@@ -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
|
||||
@@ -63,7 +59,7 @@ def print_code(outstream, name, module, info=None):
|
||||
print_code(
|
||||
target, "PgAdminModule", PgAdminModule,
|
||||
"""
|
||||
PgAdminModule is inherted from Flask.Blueprint module.
|
||||
PgAdminModule is inherited from Flask.Blueprint module.
|
||||
This module defines a set of methods, properties and attributes,
|
||||
that every module should implement.
|
||||
""")
|
||||
|
||||
@@ -29,9 +29,10 @@ Configuration
|
||||
|
||||
The core application configuration is found in **config.py**. This file includes
|
||||
all configurable settings for the application, along with descriptions of their
|
||||
use. It is essential that various settings are configured prior to deployent on
|
||||
a web server; these can be overriden in **config_local.py** to avoid modifying
|
||||
the main configuration file.
|
||||
use. It is essential that various settings are configured prior to deployment on
|
||||
a web server; these can be overridden in **config_local.py** or
|
||||
**config_system.py** (see the :ref:`config.py <config_py>` documentation) to
|
||||
avoid modifying the main configuration file.
|
||||
|
||||
User Settings
|
||||
=============
|
||||
@@ -108,7 +109,7 @@ PgAdminModule class. This is responsible for providing hook points to integrate
|
||||
the module into the rest of the application - for example, a hook might tell
|
||||
the caller what CSS files need to be included on the rendered page, or what menu
|
||||
options to include and what they should do. Hook points need not exist if they
|
||||
are not required. It is the responsiblity of the caller to ensure they are
|
||||
are not required. It is the responsibility of the caller to ensure they are
|
||||
present before attempting to utilise them.
|
||||
|
||||
Hooks currently implemented are:
|
||||
@@ -210,6 +211,6 @@ bootstrap for UI look and feel, Backbone for data manipulation of a node,
|
||||
Backform for generating properties/create dialog for selected node. We have
|
||||
divided each module in small chunks as much as possible. Not all javascript
|
||||
modules are required to be loaded (i.e. loading a javascript module for
|
||||
database will make sense only when a server node is loaded competely.) Please
|
||||
database will make sense only when a server node is loaded completely.) Please
|
||||
look at the the javascript files node.js, browser.js, menu.js, panel.js, etc for
|
||||
better understanding of the code.
|
||||
@@ -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
|
||||
@@ -212,8 +208,8 @@ htmlhelp_basename = 'pgadmin4'
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'pgadmin4.tex', u'pgAdmin 4 Documentation',
|
||||
u'The pgAdmin Development Team', 'manual'),
|
||||
('index', 'pgadmin4.tex', 'pgAdmin 4 Documentation',
|
||||
'The pgAdmin Development Team', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
@@ -251,6 +247,6 @@ latex_elements = {
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'pgadmin4', u'pgAdmin 4 Documentation',
|
||||
[u'The pgAdmin Development Team'], 1)
|
||||
('index', 'pgadmin4', 'pgAdmin 4 Documentation',
|
||||
['The pgAdmin Development Team'], 1)
|
||||
]
|
||||
@@ -23,10 +23,21 @@ are as follows:
|
||||
and may be created by users in the same directory as ``config.py`` if
|
||||
needed.
|
||||
|
||||
.. note:: If the SERVER_MODE setting is changed in ``config_distro.py`` or ``config_local.py``,
|
||||
you will most likely need to re-set the LOG_FILE, SQLITE_PATH, SESSION_DB_PATH
|
||||
and STORAGE_DIR values as well as they will have been set based on the default
|
||||
configuration or overridden by the runtime.
|
||||
* ``config_system.py``: This file is read after ``config_local.py`` and is
|
||||
intended for system administrators to include settings that are configured
|
||||
system-wide from a secure location that users cannot normally modify and that
|
||||
is outside of the pgAdmin installation. The location for this file varies
|
||||
based on the platform, and only needs to be created if desired:
|
||||
|
||||
* Linux: ``/etc/pgadmin/config_system.py``
|
||||
* macOS: ``/Library/Preferences/pgadmin/config_system.py``
|
||||
* Windows: ``%CommonProgramFiles%\pgadmin\config_system.py``
|
||||
|
||||
.. note:: If the SERVER_MODE setting is changed in ``config_distro.py``,
|
||||
``config_local.py``, or ``config_system.py`` you will most likely need to
|
||||
re-set the LOG_FILE, SQLITE_PATH, SESSION_DB_PATH and STORAGE_DIR values
|
||||
as well as they will have been set based on the default configuration or
|
||||
overridden by the runtime.
|
||||
|
||||
The default ``config.py`` file is shown below for reference:
|
||||
|
||||
|
||||
@@ -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*
|
||||
@@ -52,7 +51,7 @@ connections.
|
||||
|
||||
When TLS is enabled, a certificate and key must be provided. Typically these
|
||||
should be stored on the host file system and mounted from the container. The
|
||||
expected paths are /certs/server.crt and /certs/server.key
|
||||
expected paths are /certs/server.cert and /certs/server.key
|
||||
|
||||
**PGADMIN_LISTEN_ADDRESS**
|
||||
|
||||
@@ -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**
|
||||
|
||||
@@ -319,7 +318,7 @@ adjusted as appropriate to the specific deployment:
|
||||
listen 443;
|
||||
server_name _;
|
||||
|
||||
ssl_certificate /etc/nginx/server.crt;
|
||||
ssl_certificate /etc/nginx/server.cert;
|
||||
ssl_certificate_key /etc/nginx/server.key;
|
||||
|
||||
ssl on;
|
||||
|
||||
@@ -97,6 +97,19 @@ Follow these steps to add additional parameter value definitions; to discard a
|
||||
parameter, click the trash icon to the left of the row and confirm deletion in
|
||||
the *Delete Row* popup.
|
||||
|
||||
Click the *Advanced* tab to continue.
|
||||
|
||||
.. image:: images/database_advanced.png
|
||||
:alt: Database dialog advanced tab
|
||||
:align: center
|
||||
|
||||
Use the *Advanced* tab to set advanced parameters for the database.
|
||||
|
||||
* Use *Schema restriction* field to provide a SQL restriction that will be used
|
||||
against the pg_namespace table to limit the schemas that you see.
|
||||
For example, you might enter: *public* so that only *public* are shown in
|
||||
the pgAdmin browser.Separate entries with a comma or tab as you type.
|
||||
|
||||
Click the *SQL* tab to continue.
|
||||
|
||||
Your entries in the *Database* dialog generate a SQL command (see an example
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -5,9 +5,19 @@
|
||||
**************************************************
|
||||
|
||||
To enable LDAP authentication for pgAdmin, you must configure the LDAP
|
||||
settings in the *config_local.py* or *config_distro.py* file on the system where
|
||||
pgAdmin is installed in Server mode. You can copy these settings from *config.py*
|
||||
file and modify the values for the following parameters:
|
||||
settings in the *config_local.py* or *config_system.py* file (see the
|
||||
:ref:`config.py <config_py>` documentation) on the system where pgAdmin is
|
||||
installed in Server mode. You can copy these settings from *config.py* file
|
||||
and modify the values for the following parameters:
|
||||
|
||||
There are 3 ways to configure LDAP:
|
||||
|
||||
* Bind as pgAdmin user
|
||||
|
||||
* Anonymous bind
|
||||
|
||||
* Dedicated user bind
|
||||
|
||||
|
||||
.. csv-table::
|
||||
:header: "**Parameter**", "**Description**"
|
||||
@@ -21,9 +31,12 @@ file and modify the values for the following parameters:
|
||||
* [‘ldap’]: pgAdmin will use only LDAP authentication.
|
||||
|
||||
* [‘ldap’, ‘internal’]: pgAdmin will first try to authenticate the user through
|
||||
LDAP. If that authentication fails, then internal user entries of pgAdmin will be used for authentication.
|
||||
LDAP. If that authentication fails, then internal user entries of pgAdmin
|
||||
will be used for authentication.
|
||||
|
||||
* [‘internal’, ‘ldap’]: pgAdmin will first try to authenticate the user through internal user entries. If that authentication fails, then LDAP authentication will be used."
|
||||
* [‘internal’, ‘ldap’]: pgAdmin will first try to authenticate the user
|
||||
through internal user entries. If that authentication fails, then LDAP
|
||||
authentication will be used."
|
||||
"LDAP_AUTO_CREATE_USER", "Specifies if you want to automatically create a pgAdmin
|
||||
user corresponding to the LDAP user credentials. Please note that LDAP password
|
||||
is not stored in the pgAdmin database."
|
||||
@@ -34,10 +47,6 @@ file and modify the values for the following parameters:
|
||||
want to connect to. For example, 'ldap://172.16.209.35:389' is a valid
|
||||
LDAP_SERVER_URI where ldap is the connection protocol, 172.16.209.35 is the IP
|
||||
address and 389 is the port. Port 636 is used for the ldaps communication protocol."
|
||||
"LDAP_BASE_DN","Specifies the base DN from where a server will start the search
|
||||
for users. For example, an LDAP search for any user will be performed by the server
|
||||
starting at the base DN (dc=example,dc=com). When the base DN matches, the full
|
||||
DN (cn=admin,dc=example,dc=com) is used to bind with the supplied password."
|
||||
"LDAP_USERNAME_ATTRIBUTE","Specifies the LDAP attribute that contains the
|
||||
usernames. For LDAP authentication, you need to enter the value of that
|
||||
particular attribute as username. For example, if you set the value of
|
||||
@@ -45,10 +54,16 @@ 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 only while binding as pgAdmin user.
|
||||
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."
|
||||
@@ -70,3 +85,21 @@ file and modify the values for the following parameters:
|
||||
"LDAP_KEY_FILE","Specifies the path to the server private key file. This parameter
|
||||
is applicable only if you are using *ldaps* as connection protocol and you have
|
||||
set *LDAP_USE_STARTTLS* parameter to *True*."
|
||||
"**Bind as pgAdmin user**"
|
||||
"LDAP_BASE_DN","Specifies the base DN from where a server will start the search
|
||||
for users. For example, an LDAP search for any user will be performed by the server
|
||||
starting at the base DN (dc=example,dc=com). When the base DN matches, the full
|
||||
DN (cn=admin,dc=example,dc=com) is used to bind with the supplied password."
|
||||
"**Anonymous bind**"
|
||||
"LDAP_ANONYMOUS_BIND","Set this parameter to *True* for anonymous binding.
|
||||
After the connection is made, the pgadmin login user will be further authenticated
|
||||
by the username and password provided at the login screen."
|
||||
"**Dedicated user bind**"
|
||||
"LDAP_BIND_USER", "The account of the user to log in for simple bind.
|
||||
Set this parameter to allow the connection to bind using a dedicated user.
|
||||
After the connection is made, the pgadmin login user will be further
|
||||
authenticated by the username and password provided at the login screen.
|
||||
at the login screen."
|
||||
"LDAP_BIND_PASSWORD", "Password for simple bind.
|
||||
Specify the value if you have set the LDAP_BIND_USER parameter."
|
||||
|
||||
|
After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 223 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 303 KiB After Width: | Height: | Size: 435 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 295 KiB After Width: | Height: | Size: 364 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 302 KiB |
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 119 KiB |
@@ -23,7 +23,11 @@ the ``--dump-servers`` command line option, followed by the name (and if require
|
||||
path) to the desired output file. By default, servers owned by the desktop mode
|
||||
user will be dumped (pgadmin4@pgadmin.org by default - see the DESKTOP_USER
|
||||
setting in ``config.py``). This can be overridden with the ``--user`` command
|
||||
line option. For example:
|
||||
line option. There can be multiple configuations of pgAdmin on the same system.
|
||||
To dump the servers from specific pgAdmin config DB file, ``--sqlite-path`` option
|
||||
can be used. It is also recommended to use this option when running pgAdmin in
|
||||
desktop mode. By default SQLITE_PATH setting in ``config.py`` is taken.
|
||||
For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -33,6 +37,10 @@ line option. For example:
|
||||
|
||||
/path/to/python /path/to/setup.py --dump-servers output_file.json --user user@example.com
|
||||
|
||||
# to specify a pgAdmin config DB file:
|
||||
|
||||
/path/to/python /path/to/setup.py --dump-servers output_file.json --sqlite-path /path/to/pgadmin4.db
|
||||
|
||||
To export only certain servers, use the ``--servers`` option and list one or
|
||||
more server IDs. For example:
|
||||
|
||||
@@ -48,7 +56,10 @@ the ``--load-servers`` command line option, followed by the name (and if require
|
||||
path) of the JSON file containing the server definitions. Servers will be owned
|
||||
by the desktop mode user (pgadmin4@pgadmin.org by default - see the DESKTOP_USER
|
||||
setting in ``config.py``). This can be overridden with the ``--user`` command
|
||||
line option. For example:
|
||||
line option. There can be multiple configuations of pgAdmin on the same system.
|
||||
To load the servers into a specific pgAdmin config DB file, ``--sqlite-path`` option
|
||||
can be used. It is also recommended to use this option when running pgAdmin in
|
||||
desktop mode. By default SQLITE_PATH setting in ``config.py`` is taken. For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -58,6 +69,10 @@ line option. For example:
|
||||
|
||||
/path/to/python /path/to/setup.py --load-servers input_file.json --user user@example.com
|
||||
|
||||
# to specify a pgAdmin config DB file:
|
||||
|
||||
/path/to/python /path/to/setup.py --load-servers input_file.json --sqlite-path /path/to/pgadmin4.db
|
||||
|
||||
If any Servers are defined with a Server Group that is not already present in
|
||||
the configuration database, the required Group will be created.
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ Use the fields in the *Definition* tab to define the index:
|
||||
* Select *hash* to create a hash index. A hash index may improve
|
||||
performance when managing simple equality comparisons.
|
||||
* Select *gist* to create a GiST index. A GiST index may improve
|
||||
performance when managing two-dimensional geometric data types and
|
||||
nearest-neighbor searches.
|
||||
* Select *gin* to create a GIN index. A GIN index may improve
|
||||
performance when managing values with more than one key.
|
||||
* Select *gin* to create a GIN index. A GIN index may improve performance
|
||||
when managing two-dimensional geometric data types and nearest-neighbor
|
||||
searches.
|
||||
* Select *spgist* to create a space-partitioned GiST index. A SP-GiST index
|
||||
may improve performance when managing non-balanced data structures.
|
||||
* Select *brin* to create a BRIN index. A BRIN index may improve
|
||||
@@ -108,4 +108,4 @@ the values in the *code* column of the *distributors* table.
|
||||
* Click the *Info* button (i) to access online help.
|
||||
* Click the *Save* button to save work.
|
||||
* Click the *Cancel* button to exit without saving work.
|
||||
* Click the *Reset* button to restore configuration parameters.
|
||||
* Click the *Reset* button to restore configuration parameters.
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ node, and select *Create Cast...*
|
||||
foreign_key_dialog
|
||||
index_dialog
|
||||
primary_key_dialog
|
||||
rls_policy_dialog
|
||||
rule_dialog
|
||||
table_dialog
|
||||
trigger_dialog
|
||||
|
||||
@@ -49,6 +49,9 @@ Use the fields on the *Display* panel to specify general display preferences:
|
||||
the client will display the animated dialogues/notifications otherwise it
|
||||
will be unanimated.
|
||||
|
||||
* When the *Hide shared server?* switch is set to *True*, the client will hide
|
||||
all the shared servers from the browser tree.
|
||||
|
||||
* Use the *Lock layout* field to lock the UI layout at different levels. This
|
||||
can also be changed from File menu on the :ref:`menu bar <menu_bar>`
|
||||
|
||||
@@ -185,6 +188,7 @@ Expand the *Miscellaneous* node to specify miscellaneous display preferences.
|
||||
* Use the *Themes* drop-down listbox to select the theme for pgAdmin. You'll also get a preview just below the
|
||||
drop down. Note that, to apply the theme you need to refresh the pgAdmin page. You can also submit your
|
||||
own themes, check `here <https://git.postgresql.org/gitweb/?p=pgadmin4.git;a=blob_plain;f=README>`_ how.
|
||||
Currently we support Standard, Dark and High Contrast (Beta) theme.
|
||||
|
||||
The Paths Node
|
||||
**************
|
||||
@@ -305,12 +309,6 @@ Use the fields on the *Editor* panel to change settings of the query editor.
|
||||
changed to text/plain. Keyword highlighting and code folding will be disabled.
|
||||
This will improve editor performance with large files.
|
||||
|
||||
* Use the *Tab size* field to specify the number of spaces per tab character in
|
||||
the editor.
|
||||
|
||||
* When the *Use spaces* switch is set to *True*, the editor will insert spaces
|
||||
(instead of tab characters) when the tab key or auto-indent are used.
|
||||
|
||||
.. image:: images/preferences_sql_explain.png
|
||||
:alt: Preferences dialog sqleditor explain options
|
||||
:align: center
|
||||
@@ -374,13 +372,41 @@ preferences for copied data.
|
||||
* Use the *Result copy quoting* drop-down listbox to select which type of fields
|
||||
require quoting; select *All*, *None*, or *Strings*.
|
||||
|
||||
Use the fields on the *Keyboard shortcuts* panel to configure shortcuts for the
|
||||
Query Tool window navigation:
|
||||
|
||||
.. image:: images/preferences_sql_keyboard_shortcuts.png
|
||||
:alt: Preferences dialog sql keyboard shortcuts section
|
||||
:align: center
|
||||
|
||||
Use the fields on the *Keyboard shortcuts* panel to configure shortcuts for the
|
||||
Query Tool window navigation:
|
||||
|
||||
.. image:: images/preferences_sql_formatting.png
|
||||
:alt: Preferences dialog SQL Formatting section
|
||||
:align: center
|
||||
|
||||
Use the fields on the *SQL formatting* panel to specify your preferences for
|
||||
reformatting of SQL.
|
||||
|
||||
* Use the *Command-first notation* option to specify whether to place commas
|
||||
before or after column names.
|
||||
* Use the *Identifier case* option to specify whether to change identifiers
|
||||
(object names) into upper, lower, or capitalized case.
|
||||
* Use the *Keyword case* option to specify whether to change keywords into
|
||||
upper, lower, or capitalized case.
|
||||
* Use the *Re-indent aligned?* option to specify that indentations of statements
|
||||
should be changed, aligned by keywords.
|
||||
* Use the *Re-indent?* option to specify that indentations of statements should
|
||||
be changed.
|
||||
* Use the *Spaces around operators?* option to specify whether or not to include
|
||||
spaces on either side of operators.
|
||||
* Use the *Strip comments?* option to specify whether or not comments should be
|
||||
removed.
|
||||
* Use the *Tab size* option to specify the number of spaces per tab or indent.
|
||||
* Use the *Use spaces?* option to select whether to use spaces or tabs when
|
||||
indenting.
|
||||
* Use the *Wrap after N characters* option to specify the column limit for
|
||||
wrapping column separated lists (e.g. of column names in a table). If set to
|
||||
0 (zero), each item will be on it's own line.
|
||||
|
||||
The Schema Diff Node
|
||||
********************
|
||||
|
||||
@@ -390,6 +416,9 @@ Expand the *Schema Diff* node to specify your display preferences.
|
||||
:alt: Preferences schema diff
|
||||
:align: center
|
||||
|
||||
Use the *Ignore whitespaces* switch to ignores the whitespaces while comparing
|
||||
the string objects. Whitespace includes space, tabs, and CRLF.
|
||||
|
||||
Use the *Open in new browser tab* switch to indicate if you would like Schema Diff
|
||||
to open in a new tab.
|
||||
|
||||
|
||||
@@ -286,8 +286,10 @@ the *Clear* drop-down menu.
|
||||
Query History is maintained across sessions for each database on a per-user
|
||||
basis when running in Query Tool mode. In View/Edit Data mode, history is not
|
||||
retained. By default, the last 20 queries are stored for each database. This
|
||||
can be adjusted in `config_local.py` by overriding the `MAX_QUERY_HIST_STORED`
|
||||
value. See the :ref:`Deployment <deployment>` section for more information.
|
||||
can be adjusted in ``config_local.py`` or ``config_system.py`` (see the
|
||||
:ref:`config.py <config_py>` documentation) by overriding the
|
||||
`MAX_QUERY_HIST_STORED` value. See the :ref:`Deployment <deployment>` section
|
||||
for more information.
|
||||
|
||||
Connection Status
|
||||
*****************
|
||||
|
||||
@@ -1,184 +1,186 @@
|
||||
.. _query_tool_toolbar:
|
||||
|
||||
***************************
|
||||
`Query Tool Toolbar`:index:
|
||||
***************************
|
||||
|
||||
The *Query Tool* toolbar uses context-sensitive icons that provide shortcuts to
|
||||
frequently performed tasks. If an icon is highlighted, the option is enabled;
|
||||
if the icon is grayed-out, the task is disabled.
|
||||
|
||||
.. note:: The :ref:`Query Tool <query_tool>` and
|
||||
:ref:`View/Edit Data <editgrid>` tools are actually different operating
|
||||
modes of the same tool. Some controls will be disabled in either mode.
|
||||
|
||||
.. image:: images/query_toolbar.png
|
||||
:alt: Query tool toolbar
|
||||
:align: center
|
||||
|
||||
Hover over an icon in pgAdmin to display a tooltip that describes the icon's
|
||||
functionality.
|
||||
|
||||
File Options
|
||||
************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Open File* | Click the *Open File* icon to display a previously saved query in the SQL Editor. | Accesskey + O |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Save File* | Click the *Save* icon to perform a quick-save of a previously saved query, or to access the | Accesskey + S |
|
||||
| | *Save* menu: | |
|
||||
| | | |
|
||||
| | * Select *Save* to save the selected content of the SQL Editor panel in a file. | |
|
||||
| | | |
|
||||
| | * Select *Save As* to open a new browser dialog and specify a new location to which to save the | |
|
||||
| | selected content of the SQL Editor panel. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
|
||||
Editing Options
|
||||
***************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Save Data Changes* | Click the *Save Data Changes* icon to save data changes (insert, update, or delete) in the Data | F6 |
|
||||
| | Output Panel to the server. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Find* | Use the *Find* menu to search, replace, or navigate the code displayed in the SQL Editor: | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Find* to provide a search target, and search the SQL Editor contents. | Cmd+F |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Find next* to locate the next occurrence of the search target. | Cmd+G |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Find previous* to move to the last occurrence of the search target. | Cmd+Shift+G |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Persistent find* to identify all occurrences of the search target within the editor. | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Replace* to locate and replace (with prompting) individual occurrences of the target. | Cmd+Shift+F |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Replace all* to locate and replace all occurrences of the target within the editor. | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Jump* to navigate to the next occurrence of the search target. | Alt+G |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Copy* | Click the *Copy* icon to copy the content with or without header: | Accesskey + C |
|
||||
| | | |
|
||||
| | * Click the *Copy* icon to copy the content that is currently highlighted in the Data Output | |
|
||||
| | panel. | |
|
||||
| | | |
|
||||
| | * Click *Copy with headers* to copy the highlighted content along with the header. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Paste* | Click the *Paste* icon to paste a previously copied row into a new row. | Accesskey + P |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Delete* | Click the *Delete* icon to mark the selected rows for deletion. These marked rows get deleted |Accesskey + D |
|
||||
| | when you click the *Save Data Changes* icon. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Edit* | Use options on the *Edit* menu to access text editing tools; the options operate on the text | |
|
||||
| | displayed in the SQL Editor panel when in Query Tool mode: | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Indent Selection* to indent the currently selected text. | Tab |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Unindent Selection* to remove indentation from the currently selected text. | Shift+Tab |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Inline Comment Selection* to enclose any lines that contain the selection in SQL style | Cmd+/ |
|
||||
| | comment notation. | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Inline Uncomment Selection* to remove SQL style comment notation from the selected line. | Cmd+. |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Block Comment* to enclose all lines that contain the selection in C style comment | Shift+Cmd+/ |
|
||||
| | notation. This option acts as a toggle. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
|
||||
View/Edit Data Resultset Control
|
||||
********************************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Filter* | Click the *Filter* icon to set filtering and sorting criteria for the data when in View/Edit data | Accesskey + F |
|
||||
| | mode. Click the down arrow to access other filtering and sorting options: | |
|
||||
| | | |
|
||||
| | * Click *Sort/Filter* to open the sorting and filtering dialogue. In the *SQL Filter*, you can | |
|
||||
| | enter a SQL query as filtering criteria. In *Data Sorting*, you can select the column and | |
|
||||
| | specify the order for sorting. | |
|
||||
| | | |
|
||||
| | * Click *Filter by Selection* to show only the rows containing the values in the selected cells. | |
|
||||
| | | |
|
||||
| | * Click *Exclude by Selection* to show only the rows that do not contain the values in the | |
|
||||
| | selected cells. | |
|
||||
| | | |
|
||||
| | * Click *Remove Sort/Filter* to remove any previously selected sort or filtering options. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Limit Selector | Select a value in the *Limit Selector* to limit the size of the dataset to a number of rows. | Accesskey + R |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Stop* | Click the *Stop* icon to cancel the execution of the currently running query. | Accesskey + Q |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
|
||||
Query Execution
|
||||
***************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Execute/Refresh* | Click the *Execute/Refresh* icon to either execute or refresh the query highlighted in the SQL | F5 |
|
||||
| | editor panel. Click the down arrow to access other execution options: | |
|
||||
| | | |
|
||||
| | * Add a check next to *Auto-Rollback* to instruct the server to automatically roll back a | |
|
||||
| | transaction if an error occurs during the transaction. | |
|
||||
| | | |
|
||||
| | * Add a check next to *Auto-Commit* to instruct the server to automatically commit each | |
|
||||
| | transaction. Any changes made by the transaction will be visible to others, and | |
|
||||
| | durable in the event of a crash. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Explain* | Click the *Explain* icon to view an explanation plan for the current query. The result of the | F7 |
|
||||
| | EXPLAIN is displayed graphically on the *Explain* tab of the output panel, and in text | |
|
||||
| | form on the *Data Output* tab. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Explain analyze* | Click the *Explain analyze* icon to invoke an EXPLAIN ANALYZE command on the current query. | Shift+F7 |
|
||||
| | | |
|
||||
| | Navigate through the *Explain Options* menu to select options for the EXPLAIN command: | |
|
||||
| | | |
|
||||
| | * Select *Verbose* to display additional information regarding the query plan. | |
|
||||
| | | |
|
||||
| | * Select *Costs* to include information on the estimated startup and total cost of each | |
|
||||
| | plan node, as well as the estimated number of rows and the estimated width of each | |
|
||||
| | row. | |
|
||||
| | | |
|
||||
| | * Select *Buffers* to include information on buffer usage. | |
|
||||
| | | |
|
||||
| | * Select *Timing* to include information about the startup time and the amount of time | |
|
||||
| | spent in each node of the query. | |
|
||||
| | | |
|
||||
| | * Select *Summary* to include the summary information about the query plan. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Commit* | Click the *Commit* icon to commit the transaction. | Shift+CTRL+M |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Rollback* | Click the *Rollback* icon to rollback the transaction. | Shift+CTRL+R |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Clear* | Use options on the *Clear* drop-down menu to erase display contents: | Accesskey + L |
|
||||
| | | |
|
||||
| | * Select *Clear Query Window* to erase the content of the SQL Editor panel. | |
|
||||
| | | |
|
||||
| | * Select *Clear History* to erase the content of the *History* tab. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
.. _query_tool_toolbar:
|
||||
|
||||
***************************
|
||||
`Query Tool Toolbar`:index:
|
||||
***************************
|
||||
|
||||
The *Query Tool* toolbar uses context-sensitive icons that provide shortcuts to
|
||||
frequently performed tasks. If an icon is highlighted, the option is enabled;
|
||||
if the icon is grayed-out, the task is disabled.
|
||||
|
||||
.. note:: The :ref:`Query Tool <query_tool>` and
|
||||
:ref:`View/Edit Data <editgrid>` tools are actually different operating
|
||||
modes of the same tool. Some controls will be disabled in either mode.
|
||||
|
||||
.. image:: images/query_toolbar.png
|
||||
:alt: Query tool toolbar
|
||||
:align: center
|
||||
|
||||
Hover over an icon in pgAdmin to display a tooltip that describes the icon's
|
||||
functionality.
|
||||
|
||||
File Options
|
||||
************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Open File* | Click the *Open File* icon to display a previously saved query in the SQL Editor. | Accesskey + O |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Save File* | Click the *Save* icon to perform a quick-save of a previously saved query, or to access the | Accesskey + S |
|
||||
| | *Save* menu: | |
|
||||
| | | |
|
||||
| | * Select *Save* to save the selected content of the SQL Editor panel in a file. | |
|
||||
| | | |
|
||||
| | * Select *Save As* to open a new browser dialog and specify a new location to which to save the | |
|
||||
| | selected content of the SQL Editor panel. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
|
||||
Editing Options
|
||||
***************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Save Data Changes* | Click the *Save Data Changes* icon to save data changes (insert, update, or delete) in the Data | F6 |
|
||||
| | Output Panel to the server. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Find* | Use the *Find* menu to search, replace, or navigate the code displayed in the SQL Editor: | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Find* to provide a search target, and search the SQL Editor contents. | Cmd+F |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Find next* to locate the next occurrence of the search target. | Cmd+G |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Find previous* to move to the last occurrence of the search target. | Cmd+Shift+G |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Persistent find* to identify all occurrences of the search target within the editor. | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Replace* to locate and replace (with prompting) individual occurrences of the target. | Cmd+Shift+F |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Replace all* to locate and replace all occurrences of the target within the editor. | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Jump* to navigate to the next occurrence of the search target. | Alt+G |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Copy* | Click the *Copy* icon to copy the content with or without header: | Accesskey + C |
|
||||
| | | |
|
||||
| | * Click the *Copy* icon to copy the content that is currently highlighted in the Data Output | |
|
||||
| | panel. | |
|
||||
| | | |
|
||||
| | * Click *Copy with headers* to copy the highlighted content along with the header. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Paste* | Click the *Paste* icon to paste a previously copied row into a new row. | Accesskey + P |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Delete* | Click the *Delete* icon to mark the selected rows for deletion. These marked rows get deleted |Accesskey + D |
|
||||
| | when you click the *Save Data Changes* icon. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Edit* | Use options on the *Edit* menu to access text editing tools; the options operate on the text | |
|
||||
| | displayed in the SQL Editor panel when in Query Tool mode: | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Indent Selection* to indent the currently selected text. | Tab |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Unindent Selection* to remove indentation from the currently selected text. | Shift+Tab |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Inline Comment Selection* to enclose any lines that contain the selection in SQL style | Cmd+/ |
|
||||
| | comment notation. | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Inline Uncomment Selection* to remove SQL style comment notation from the selected line. | Cmd+. |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Block Comment* to enclose all lines that contain the selection in C style comment | Shift+Cmd+/ |
|
||||
| | notation. This option acts as a toggle. | |
|
||||
| +---------------------------------------------------------------------------------------------------+----------------+
|
||||
| | Select *Format SQL* to format the selected SQL or all the SQL if none is selected | Shift+Cmd+K |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
|
||||
View/Edit Data Resultset Control
|
||||
********************************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Filter* | Click the *Filter* icon to set filtering and sorting criteria for the data when in View/Edit data | Accesskey + F |
|
||||
| | mode. Click the down arrow to access other filtering and sorting options: | |
|
||||
| | | |
|
||||
| | * Click *Sort/Filter* to open the sorting and filtering dialogue. In the *SQL Filter*, you can | |
|
||||
| | enter a SQL query as filtering criteria. In *Data Sorting*, you can select the column and | |
|
||||
| | specify the order for sorting. | |
|
||||
| | | |
|
||||
| | * Click *Filter by Selection* to show only the rows containing the values in the selected cells. | |
|
||||
| | | |
|
||||
| | * Click *Exclude by Selection* to show only the rows that do not contain the values in the | |
|
||||
| | selected cells. | |
|
||||
| | | |
|
||||
| | * Click *Remove Sort/Filter* to remove any previously selected sort or filtering options. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Limit Selector | Select a value in the *Limit Selector* to limit the size of the dataset to a number of rows. | Accesskey + R |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Stop* | Click the *Stop* icon to cancel the execution of the currently running query. | Accesskey + Q |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
|
||||
Query Execution
|
||||
***************
|
||||
|
||||
.. table::
|
||||
:class: longtable
|
||||
:widths: 1 4 1
|
||||
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| Icon | Behavior | Shortcut |
|
||||
+======================+===================================================================================================+================+
|
||||
| *Execute/Refresh* | Click the *Execute/Refresh* icon to either execute or refresh the query highlighted in the SQL | F5 |
|
||||
| | editor panel. Click the down arrow to access other execution options: | |
|
||||
| | | |
|
||||
| | * Add a check next to *Auto-Rollback* to instruct the server to automatically roll back a | |
|
||||
| | transaction if an error occurs during the transaction. | |
|
||||
| | | |
|
||||
| | * Add a check next to *Auto-Commit* to instruct the server to automatically commit each | |
|
||||
| | transaction. Any changes made by the transaction will be visible to others, and | |
|
||||
| | durable in the event of a crash. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Explain* | Click the *Explain* icon to view an explanation plan for the current query. The result of the | F7 |
|
||||
| | EXPLAIN is displayed graphically on the *Explain* tab of the output panel, and in text | |
|
||||
| | form on the *Data Output* tab. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Explain analyze* | Click the *Explain analyze* icon to invoke an EXPLAIN ANALYZE command on the current query. | Shift+F7 |
|
||||
| | | |
|
||||
| | Navigate through the *Explain Options* menu to select options for the EXPLAIN command: | |
|
||||
| | | |
|
||||
| | * Select *Verbose* to display additional information regarding the query plan. | |
|
||||
| | | |
|
||||
| | * Select *Costs* to include information on the estimated startup and total cost of each | |
|
||||
| | plan node, as well as the estimated number of rows and the estimated width of each | |
|
||||
| | row. | |
|
||||
| | | |
|
||||
| | * Select *Buffers* to include information on buffer usage. | |
|
||||
| | | |
|
||||
| | * Select *Timing* to include information about the startup time and the amount of time | |
|
||||
| | spent in each node of the query. | |
|
||||
| | | |
|
||||
| | * Select *Summary* to include the summary information about the query plan. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Commit* | Click the *Commit* icon to commit the transaction. | Shift+CTRL+M |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Rollback* | Click the *Rollback* icon to rollback the transaction. | Shift+CTRL+R |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Clear* | Use options on the *Clear* drop-down menu to erase display contents: | Accesskey + L |
|
||||
| | | |
|
||||
| | * Select *Clear Query Window* to erase the content of the SQL Editor panel. | |
|
||||
| | | |
|
||||
| | * Select *Clear History* to erase the content of the *History* tab. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
| *Download as CSV/TXT*| Click the *Download as CSV/TXT* icon to download the result set of the current query as a *.csv* | F8 |
|
||||
| | or as a *.txt* file. if *CSV field seperator* set to comma(,) else as a *.txt* file. | |
|
||||
| | You can specify the CSV/TXT settings through *Preferences -> SQL Editor -> CSV/TXT output* | |
|
||||
| | dialogue. | |
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
+----------------------+---------------------------------------------------------------------------------------------------+----------------+
|
||||
@@ -11,6 +11,11 @@ notes for it.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
release_notes_4_26
|
||||
release_notes_4_25
|
||||
release_notes_4_24
|
||||
release_notes_4_23
|
||||
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.
|
||||
@@ -0,0 +1,38 @@
|
||||
************
|
||||
Version 4.23
|
||||
************
|
||||
|
||||
Release date: 2020-06-25
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin4 4.22.
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #5468 <https://redmine.postgresql.org/issues/5468>`_ - Added option to ignore the whitespaces while comparing objects in schema diff.
|
||||
| `Issue #5500 <https://redmine.postgresql.org/issues/5500>`_ - Added server group name while selecting servers in schema diff.
|
||||
| `Issue #5516 <https://redmine.postgresql.org/issues/5516>`_ - Added support of Row Security Policies.
|
||||
| `Issue #5576 <https://redmine.postgresql.org/issues/5576>`_ - Improve error messaging if the storage and log directories cannot be created.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
| `Issue #5325 <https://redmine.postgresql.org/issues/5325>`_ - Improve code coverage and API test cases for Collations.
|
||||
| `Issue #5574 <https://redmine.postgresql.org/issues/5574>`_ - Cleanup Windows build scripts and ensure Windows x64 builds will work.
|
||||
| `Issue #5581 <https://redmine.postgresql.org/issues/5581>`_ - Documentation of Row Level Security Policies.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #3591 <https://redmine.postgresql.org/issues/3591>`_ - Ensure that the query tool should display the proper error message while terminating the active session.
|
||||
| `Issue #3669 <https://redmine.postgresql.org/issues/3669>`_ - Ensure that proper error should be displayed for the deleted node.
|
||||
| `Issue #3787 <https://redmine.postgresql.org/issues/3787>`_ - Disabled the Stop process button after clicking it and added a message 'Terminating the process...' to notify the user.
|
||||
| `Issue #4226 <https://redmine.postgresql.org/issues/4226>`_ - Fixed an issue where select all checkbox only selects the first 50 tables.
|
||||
| `Issue #5416 <https://redmine.postgresql.org/issues/5416>`_ - Ensure that the query tool panel gets closed when clicking on the 'Don't Save' button.
|
||||
| `Issue #5465 <https://redmine.postgresql.org/issues/5465>`_ - Fixed an issue where the Edge browser version is showing wrong and warning message gets displayed.
|
||||
| `Issue #5492 <https://redmine.postgresql.org/issues/5492>`_ - Fixed an issue where the search object is unable to locate inherited tables and constraint filters are not working.
|
||||
| `Issue #5507 <https://redmine.postgresql.org/issues/5507>`_ - Fixed connection and version number detection issue when the database server is upgraded.
|
||||
| `Issue #5521 <https://redmine.postgresql.org/issues/5521>`_ - Fixed an issue when dumping servers from a desktop pgAdmin app by providing an option '--sqlite-path'.
|
||||
| `Issue #5539 <https://redmine.postgresql.org/issues/5539>`_ - Fixed typo in exception keyword.
|
||||
| `Issue #5584 <https://redmine.postgresql.org/issues/5584>`_ - Fixed an issue where two identical tables showing different by schema diff tool.
|
||||
| `Issue #5592 <https://redmine.postgresql.org/issues/5592>`_ - Ensure that pgadmin should be able to connect to the server which has password more than 1000 characters.
|
||||
@@ -0,0 +1,53 @@
|
||||
************
|
||||
Version 4.24
|
||||
************
|
||||
|
||||
Release date: 2020-07-23
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin4 4.23.
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #5235 <https://redmine.postgresql.org/issues/5235>`_ - Support configuration files that are external to the application installation.
|
||||
| `Issue #5484 <https://redmine.postgresql.org/issues/5484>`_ - Added support for LDAP authentication with different DN by setting the dedicated user for the LDAP connection.
|
||||
| `Issue #5583 <https://redmine.postgresql.org/issues/5583>`_ - Added support for schema level restriction.
|
||||
| `Issue #5601 <https://redmine.postgresql.org/issues/5601>`_ - Added RLS Policy support in Schema Diff.
|
||||
| `Issue #5622 <https://redmine.postgresql.org/issues/5622>`_ - Added support for permissive/restricted policy type while creating RLS Policy.
|
||||
| `Issue #5650 <https://redmine.postgresql.org/issues/5650>`_ - Added support for LDAP anonymous binding.
|
||||
| `Issue #5653 <https://redmine.postgresql.org/issues/5653>`_ - Added High Contrast theme support.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
| `Issue #5323 <https://redmine.postgresql.org/issues/5323>`_ - Improve code coverage and API test cases for Foreign Data Wrapper.
|
||||
| `Issue #5326 <https://redmine.postgresql.org/issues/5326>`_ - Improve code coverage and API test cases for Domain and Domain Constraints.
|
||||
| `Issue #5329 <https://redmine.postgresql.org/issues/5329>`_ - Improve code coverage and API test cases for FTS Configuration, FTS Parser, FTS Dictionaries, and FTS Template.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #3814 <https://redmine.postgresql.org/issues/3814>`_ - Fixed issue of error message not getting displayed when filename is empty for backup, restore, and import/export.
|
||||
| `Issue #3851 <https://redmine.postgresql.org/issues/3851>`_ - Add proper indentation to the code while generating functions, procedures, and trigger functions.
|
||||
| `Issue #4235 <https://redmine.postgresql.org/issues/4235>`_ - Fixed tab indent issue on a selection of lines is deleting the content when 'use spaces == true' in the preferences.
|
||||
| `Issue #5137 <https://redmine.postgresql.org/issues/5137>`_ - Fixed save button enable issue when focusing in and out of numeric input field.
|
||||
| `Issue #5287 <https://redmine.postgresql.org/issues/5287>`_ - Fixed dark theme-related CSS and modify the color codes.
|
||||
| `Issue #5414 <https://redmine.postgresql.org/issues/5414>`_ - Use QStandardPaths::AppLocalDataLocation in the runtime to determine where to store runtime logs.
|
||||
| `Issue #5463 <https://redmine.postgresql.org/issues/5463>`_ - Fixed an issue where CSV download quotes numeric columns.
|
||||
| `Issue #5470 <https://redmine.postgresql.org/issues/5470>`_ - Fixed backgrid row hover issue where on hover background color is set for edit and delete cell only.
|
||||
| `Issue #5530 <https://redmine.postgresql.org/issues/5530>`_ - Ensure that the referenced table should be displayed on foreign key constraints.
|
||||
| `Issue #5554 <https://redmine.postgresql.org/issues/5554>`_ - Replace the runtime themes with ones that don't have sizing issues.
|
||||
| `Issue #5569 <https://redmine.postgresql.org/issues/5569>`_ - Fixed reverse engineered SQL for partitions when storage parameters are specified.
|
||||
| `Issue #5577 <https://redmine.postgresql.org/issues/5577>`_ - Include LICENSE and DEPENDENCIES [inventory] files in official packages.
|
||||
| `Issue #5621 <https://redmine.postgresql.org/issues/5621>`_ - Remove extra brackets from reverse engineering SQL of RLS Policy.
|
||||
| `Issue #5629 <https://redmine.postgresql.org/issues/5629>`_ - Fixed an issue where the user is able to edit properties when some of the collection nodes are selected.
|
||||
| `Issue #5630 <https://redmine.postgresql.org/issues/5630>`_ - Fixed an issue where installation of pgadmin4 not working on 32-bit Windows.
|
||||
| `Issue #5631 <https://redmine.postgresql.org/issues/5631>`_ - Fixed 'cant execute empty query' issue when remove the value of 'USING' or 'WITH CHECK' option of RLS Policy.
|
||||
| `Issue #5633 <https://redmine.postgresql.org/issues/5633>`_ - Ensure that create RLS Policy menu should not be visible for catalog objects.
|
||||
| `Issue #5647 <https://redmine.postgresql.org/issues/5647>`_ - Fixed an issue where difference DDL is showing the wrong SQL when changing the policy owner.
|
||||
| `Issue #5662 <https://redmine.postgresql.org/issues/5662>`_ - Fixed accessibility issue where few dialogs are not rendering properly when we zoomed in browser window 200% and screen resolution is low.
|
||||
| `Issue #5666 <https://redmine.postgresql.org/issues/5666>`_ - Added missing dependencies/dependent and corrected some wrongly identified.
|
||||
| `Issue #5673 <https://redmine.postgresql.org/issues/5673>`_ - Fixed an issue where fetching the schema throws an error if the database is not connected in Schema Diff.
|
||||
| `Issue #5675 <https://redmine.postgresql.org/issues/5675>`_ - Fixed CSRF errors when pgAdmin opened in an iframe on safari browser.
|
||||
| `Issue #5677 <https://redmine.postgresql.org/issues/5677>`_ - Fixed text color issue in explain analyze for the Dark theme.
|
||||
| `Issue #5686 <https://redmine.postgresql.org/issues/5686>`_ - Fixed issue where the user was not able to update policy if the policy is created with space.
|
||||
@@ -0,0 +1,49 @@
|
||||
************
|
||||
Version 4.25
|
||||
************
|
||||
|
||||
Release date: 2020-08-20
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin4 4.24.
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #3904 <https://redmine.postgresql.org/issues/3904>`_ - Replace charting library Flotr2 with ChartJS using React.
|
||||
| `Issue #5126 <https://redmine.postgresql.org/issues/5126>`_ - Modified schema diff tool to compare two databases instead of two schemas.
|
||||
| `Issue #5610 <https://redmine.postgresql.org/issues/5610>`_ - Add a --yes command line option to setup-web.sh to allow non-interactive use.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
| `Issue #5324 <https://redmine.postgresql.org/issues/5324>`_ - Improve code coverage and API test cases for Foreign Servers and User Mappings.
|
||||
| `Issue #5327 <https://redmine.postgresql.org/issues/5327>`_ - Improve code coverage and API test cases for Schemas.
|
||||
| `Issue #5336 <https://redmine.postgresql.org/issues/5336>`_ - Improve code coverage and API test cases for Types.
|
||||
| `Issue #5700 <https://redmine.postgresql.org/issues/5700>`_ - Remove old Python 2 compatibility code.
|
||||
| `Issue #5731 <https://redmine.postgresql.org/issues/5731>`_ - Upgrade font awesome from v4 to v5.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #3767 <https://redmine.postgresql.org/issues/3767>`_ - Ensure that the original file format should be retained when saving the same file in SQL editor.
|
||||
| `Issue #3791 <https://redmine.postgresql.org/issues/3791>`_ - Added missing comments in reverse engineering SQL for each column of a View.
|
||||
| `Issue #4123 <https://redmine.postgresql.org/issues/4123>`_ - Fixed an issue where debugger doesn't work if the search path is set other than 'public'.
|
||||
| `Issue #4361 <https://redmine.postgresql.org/issues/4361>`_ - Fixed ssh tunnel hang issue when the user tries to disconnect the server.
|
||||
| `Issue #4387 <https://redmine.postgresql.org/issues/4387>`_ - Fixed an issue where the user is not able to insert the data if the table and columns name contains special characters.
|
||||
| `Issue #4810 <https://redmine.postgresql.org/issues/4810>`_ - Fixed an issue where the user is not able to save the new row if the table is empty.
|
||||
| `Issue #5429 <https://redmine.postgresql.org/issues/5429>`_ - Ensure that the Dictionaries drop-down shows all the dictionaries in the FTS configuration dialog.
|
||||
| `Issue #5490 <https://redmine.postgresql.org/issues/5490>`_ - Make the runtime configuration dialog non-modal.
|
||||
| `Issue #5526 <https://redmine.postgresql.org/issues/5526>`_ - Fixed an issue where copying and pasting a cell with multiple line data will result in multiple rows.
|
||||
| `Issue #5567 <https://redmine.postgresql.org/issues/5567>`_ - Fixed an issue where conversion of bytea to the binary string results in an error.
|
||||
| `Issue #5604 <https://redmine.postgresql.org/issues/5604>`_ - Fixed an issue where the entire logs is in red text when the user runs backup and restore.
|
||||
| `Issue #5632 <https://redmine.postgresql.org/issues/5632>`_ - Ensure that the user will be able to modify the start value of the Identity column.
|
||||
| `Issue #5646 <https://redmine.postgresql.org/issues/5646>`_ - Ensure that RLS Policy node should be searchable using search object.
|
||||
| `Issue #5664 <https://redmine.postgresql.org/issues/5664>`_ - Fixed an issue where 'ALTER VIEW' statement is missing when the user sets the default value of a column for View.
|
||||
| `Issue #5670 <https://redmine.postgresql.org/issues/5670>`_ - Fixed an issue where the error message does not have a close button on utility dialogs.
|
||||
| `Issue #5689 <https://redmine.postgresql.org/issues/5689>`_ - Added the 'ORDER BY' clause for the privileges type to fix schema diff issue.
|
||||
| `Issue #5708 <https://redmine.postgresql.org/issues/5708>`_ - Correct TLS certificate filename in the container deployment docs.
|
||||
| `Issue #5710 <https://redmine.postgresql.org/issues/5710>`_ - Fixed an issue when comparing the table with a trigger throwing error in schema diff.
|
||||
| `Issue #5713 <https://redmine.postgresql.org/issues/5713>`_ - Corrected DROP SQL syntax for catalog.
|
||||
| `Issue #5716 <https://redmine.postgresql.org/issues/5716>`_ - Fixed an issue where ajax call continues to fire even after disconnecting the database server.
|
||||
| `Issue #5724 <https://redmine.postgresql.org/issues/5724>`_ - Clarify some of the differences when running in server mode in the docs.
|
||||
| `Issue #5730 <https://redmine.postgresql.org/issues/5730>`_ - Resolve schema diff dependencies by selecting the appropriate node automatically and maintain the order in the generated script.
|
||||
@@ -0,0 +1,49 @@
|
||||
************
|
||||
Version 4.26
|
||||
************
|
||||
|
||||
Release date: 2020-09-17
|
||||
|
||||
This release contains a number of bug fixes and new features since the release of pgAdmin4 4.25.
|
||||
|
||||
New features
|
||||
************
|
||||
|
||||
| `Issue #2042 <https://redmine.postgresql.org/issues/2042>`_ - Added SQL Formatter support in Query Tool.
|
||||
| `Issue #4059 <https://redmine.postgresql.org/issues/4059>`_ - Added a new button to the query tool toolbar to open a new query tool window.
|
||||
| `Issue #4979 <https://redmine.postgresql.org/issues/4979>`_ - Added shared server support for admin users.
|
||||
| `Issue #5772 <https://redmine.postgresql.org/issues/5772>`_ - Warn the user when connecting to a server that is older than pgAdmin supports.
|
||||
|
||||
Housekeeping
|
||||
************
|
||||
|
||||
| `Issue #5332 <https://redmine.postgresql.org/issues/5332>`_ - Improve code coverage and API test cases for Columns and Constraints (Index, Foreign Key, Check, Exclusion).
|
||||
| `Issue #5344 <https://redmine.postgresql.org/issues/5344>`_ - Improve code coverage and API test cases for Grant Wizard.
|
||||
| `Issue #5774 <https://redmine.postgresql.org/issues/5774>`_ - Improve code coverage and API test cases for Tables.
|
||||
| `Issue #5792 <https://redmine.postgresql.org/issues/5792>`_ - Added documentation for shared server support.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
| `Issue #4216 <https://redmine.postgresql.org/issues/4216>`_ - Ensure that schema names starting with 'pg' should be visible in browser tree when standard_conforming_strings is set to off.
|
||||
| `Issue #5426 <https://redmine.postgresql.org/issues/5426>`_ - Adjusted the height of jobstep code block to use maximum space.
|
||||
| `Issue #5652 <https://redmine.postgresql.org/issues/5652>`_ - Modified the 'Commit' and 'Rollback' query tool button icons.
|
||||
| `Issue #5722 <https://redmine.postgresql.org/issues/5722>`_ - Ensure that the user should be able to drop the database even if it is connected.
|
||||
| `Issue #5732 <https://redmine.postgresql.org/issues/5732>`_ - Fixed some accessibility issues.
|
||||
| `Issue #5734 <https://redmine.postgresql.org/issues/5734>`_ - Update the description of GIN and GiST indexes in the documentation.
|
||||
| `Issue #5746 <https://redmine.postgresql.org/issues/5746>`_ - Fixed an issue where --load-server does not allow loading connections that use pg_services.
|
||||
| `Issue #5748 <https://redmine.postgresql.org/issues/5748>`_ - Fixed incorrect reverse engineering SQL for Foreign key when creating a table.
|
||||
| `Issue #5751 <https://redmine.postgresql.org/issues/5751>`_ - Enable the 'Configure' and 'View log' menu option when the server taking longer than usual time to start.
|
||||
| `Issue #5754 <https://redmine.postgresql.org/issues/5754>`_ - Fixed an issue where schema diff is not working when providing the options to Foreign Data Wrapper, Foreign Server, and User Mapping.
|
||||
| `Issue #5764 <https://redmine.postgresql.org/issues/5764>`_ - Fixed SQL for Row Level Security which is incorrectly generated.
|
||||
| `Issue #5765 <https://redmine.postgresql.org/issues/5765>`_ - Fixed an issue in the query tool when columns are having the same name as javascript object internal functions.
|
||||
| `Issue #5766 <https://redmine.postgresql.org/issues/5766>`_ - Fixed string indices must be integers issue for PostgreSQL < 9.3.
|
||||
| `Issue #5773 <https://redmine.postgresql.org/issues/5773>`_ - Fixed an issue where the application ignores the fixed port configuration value.
|
||||
| `Issue #5775 <https://redmine.postgresql.org/issues/5775>`_ - Ensure that 'setup-web.sh' should work in Debian 10.
|
||||
| `Issue #5779 <https://redmine.postgresql.org/issues/5779>`_ - Remove illegal argument from trigger function in trigger DDL statement.
|
||||
| `Issue #5794 <https://redmine.postgresql.org/issues/5794>`_ - Fixed excessive CPU usage by stopping the indefinite growth of the graph dataset.
|
||||
| `Issue #5815 <https://redmine.postgresql.org/issues/5815>`_ - Fixed an issue where clicking on the 'Generate script' button shows a forever spinner due to pop up blocker.
|
||||
| `Issue #5816 <https://redmine.postgresql.org/issues/5816>`_ - Ensure that the 'CREATE SCHEMA' statement should be present in the generated script if the schema is not present in the target database.
|
||||
| `Issue #5820 <https://redmine.postgresql.org/issues/5820>`_ - Fixed an issue while refreshing Resource Group.
|
||||
| `Issue #5833 <https://redmine.postgresql.org/issues/5833>`_ - Fixed an issue where custom sequences are not visible when show system objects are set to false.
|
||||
| `Issue #5834 <https://redmine.postgresql.org/issues/5834>`_ - Ensure that the 'Remove Server Group' option is available in the context menu.
|
||||
@@ -0,0 +1,58 @@
|
||||
.. _rls_policy_dialog:
|
||||
|
||||
**************************
|
||||
`RLS Policy Dialog`:index:
|
||||
**************************
|
||||
|
||||
Use the *RLS Policy* dialog to Create a Row Level Security Policy.
|
||||
|
||||
.. note::
|
||||
|
||||
If the Row Level Security is enabled at table level and no policy is created then by default *Deny Policy* is applied. That means, no rows are visible or can be modified for that table.
|
||||
|
||||
The *RLS Policy* dialog creates a Row Level Security Policy through the following dialog tabs: *General*, and *Commands*. The *SQL* tab displays the SQL code generated by dialog selections.
|
||||
|
||||
.. image:: images/rls_policy_general_tab.png
|
||||
:alt: RLS Policy General Tab
|
||||
:align: center
|
||||
|
||||
Use the fields in the *General* tab to define the RLS Policy:
|
||||
|
||||
* Use the *Name* field to add a descriptive name for the RLS Policy. The name will be displayed in the *pgAdmin* tree control.
|
||||
* Use the drop-down listbox next to *Role* to select the Role to which the RLS Policy is to be applied.
|
||||
* Use the drop-down listbox next to *Type* to select the type of the policy.
|
||||
|
||||
Click the *Commands* tab to continue.
|
||||
|
||||
.. image:: images/rls_policy_commands_tab.png
|
||||
:alt: RLS Policy Commands Tab
|
||||
:align: center
|
||||
|
||||
Use the fields in the *Commands* tab to define the RLS Policy:
|
||||
|
||||
* Use the drop-down listbox next to *Event* to select the command to which policy applies. Valid options are ALL, SELECT, INSERT, UPDATE, and DELETE. Default is ALL.
|
||||
* Use the *Using* field to add a SQL conditional expression returning boolean. This expression will be added to queries that refer to the table if row level security is enabled.
|
||||
* Use the *With check* field to add a SQL conditional expression returning boolean. This expression will be used in INSERT and UPDATE queries against the table if row level security is enabled.
|
||||
|
||||
Click the *SQL* tab to continue.
|
||||
|
||||
Your entries in the *RLS Policy* dialog generate a SQL command (see an example
|
||||
below). Use the *SQL* tab for review; revisit or switch tabs to make any
|
||||
changes to the SQL command.
|
||||
|
||||
Example
|
||||
*******
|
||||
|
||||
The following is an example of the sql command generated by user selections in
|
||||
the *RLS Policy* dialog:
|
||||
|
||||
.. image:: images/rls_policy_sql_tab.png
|
||||
:alt: RLS Policy sql tab
|
||||
:align: center
|
||||
|
||||
The example shown demonstrates creating a RLS Policy named *account_managers* that applies the Row Level Security on the *accounts* table.
|
||||
|
||||
* Click the *Info* button (i) to access online help.
|
||||
* Click the *Save* button to save work.
|
||||
* Click the *Cancel* button to exit without saving work.
|
||||
* Click the *Reset* button to restore configuration parameters.
|
||||
@@ -4,29 +4,29 @@
|
||||
`Schema Diff`:index:
|
||||
********************
|
||||
|
||||
**Schema Diff** is a feature that allows you to compare schema objects between
|
||||
two database schemas. Use the *Tools* menu to access Schema Diff.
|
||||
**Schema Diff** is a feature that allows you to compare objects between
|
||||
two databases. Use the *Tools* menu to access Schema Diff.
|
||||
|
||||
The Schema Diff feature allows you to:
|
||||
|
||||
* Compare and synchronize the database schemas (from source to target).
|
||||
* Compare and synchronize the database objects (from source to target).
|
||||
|
||||
* Visualize the differences between database schemas.
|
||||
* Visualize the differences between database objects.
|
||||
|
||||
* List the differences in SQL statement for target schema objects.
|
||||
* List the differences in SQL statement for target database objects.
|
||||
|
||||
* Generate synchronization scripts.
|
||||
|
||||
|
||||
**Note** - The source and target databases must be of the same major
|
||||
**Note** - The source and target database servers must be of the same major
|
||||
version.
|
||||
|
||||
Click on *Schema Diff* under the *Tools* menu to open a selection panel. Choose
|
||||
the source and target servers, databases, and schemas that will be
|
||||
the source and target servers, and databases that will be
|
||||
compared. After selecting the objects, click on the *Compare* button.
|
||||
|
||||
You can open multiple copies of *Schema Diff* in individual tabs
|
||||
simultaneously. To close a copy of Schema Diff, click the *X* in the
|
||||
simultaneously. To close a copy of Schema Diff, click the *X* in the
|
||||
upper-right hand corner of the tab bar.
|
||||
|
||||
.. image:: images/schema_diff_dialog.png
|
||||
@@ -44,7 +44,7 @@ The Schema Diff Object Comparison Panel
|
||||
========================================
|
||||
|
||||
In the object comparison panel, you can select the source and target servers
|
||||
of the same major version, databases, and schemas to be compared. You can
|
||||
of the same major version, and databases to be compared. You can
|
||||
select any server listed under the browser tree whether it is connected or
|
||||
disconnected. If you select a server that is not connected then it will
|
||||
prompt you for the password before using the server.
|
||||
@@ -52,40 +52,36 @@ prompt you for the password before using the server.
|
||||
Next, select the databases that will be compared. The databases can be the
|
||||
same or different (and within the same server or from different servers).
|
||||
|
||||
Lastly, select the source and target schemas which will be compared.
|
||||
|
||||
.. image:: images/schema_diff_compare_button.png
|
||||
:alt: Schema diff compare button
|
||||
:align: center
|
||||
|
||||
After you select servers, databases, and schemas, click on the
|
||||
After you select servers, and databases, click on the
|
||||
*Compare* button to obtain the *Comparison Result*.
|
||||
|
||||
.. image:: images/schema_diff_comparison_results.png
|
||||
:alt: Schema diff comparison results
|
||||
:align: center
|
||||
|
||||
Use the drop-down lists of Functions, Materialized Views, Tables,
|
||||
Trigger Functions, Procedures, and Views to view the DDL statements of
|
||||
all the schema objects.
|
||||
Use the drop-down lists of Database Objects to view the DDL statements.
|
||||
|
||||
In the upper-right hand corner of the object comparison panel is a *Filter*
|
||||
option that you can use to filter the schema objects based on the
|
||||
option that you can use to filter the database objects based on the
|
||||
following comparison criteria:
|
||||
|
||||
* Identical – If the object is found in both schemas with the same SQL statement, then the comparison result is identical.
|
||||
* Identical – If the object is found in both databases with the same SQL statement, then the comparison result is identical.
|
||||
|
||||
* Different – If the object is found in both schemas but have different SQL statements, then the comparison result is different.
|
||||
* Different – If the object is found in both databases but have different SQL statements, then the comparison result is different.
|
||||
|
||||
* Source Only – If the object is found in source schema only and not in target schema, then the comparison result is source only.
|
||||
* Source Only – If the object is found in source database only and not in target database, then the comparison result is source only.
|
||||
|
||||
* Target Only – If the object is found in target schema only and not in source schema, then the comparison result is target only.
|
||||
* Target Only – If the object is found in target database only and not in source database, then the comparison result is target only.
|
||||
|
||||
.. image:: images/schema_diff_filter_option.png
|
||||
:alt: Schema diff filter option
|
||||
:align: center
|
||||
|
||||
Click on any of the schema objects in the object comparison panel to
|
||||
Click on any of the database objects in the object comparison panel to
|
||||
display the DDL Statements of that object in the DDL Comparison panel.
|
||||
|
||||
|
||||
@@ -94,36 +90,32 @@ Schema Diff DDL Comparison Panel
|
||||
|
||||
The *DDL Comparison* panel displays three columns:
|
||||
|
||||
* The first column displays the DDL statement of the object from the source schema.
|
||||
* The first column displays the DDL statement of the object from the source database.
|
||||
|
||||
* The second column displays the DDL statement of the object from the target schema.
|
||||
* The second column displays the DDL statement of the object from the target database.
|
||||
|
||||
* The third column displays the difference in the SQL statement of the target schema object.
|
||||
* The third column displays the difference in the SQL statement of the target database object.
|
||||
|
||||
.. image:: images/schema_diff_DDL_comparison.png
|
||||
:alt: Schema diff DDL comparison
|
||||
:align: center
|
||||
|
||||
You can review the DDL statements of all the schema objects to
|
||||
You can review the DDL statements of all the database objects to
|
||||
check for the differences in the SQL statements.
|
||||
|
||||
Also, you can generate the SQL script of the differences found in the
|
||||
target schema object based on the SQL statement of the source schema
|
||||
object. To generate the script, select the checkboxes of the schema
|
||||
target database object based on the SQL statement of the source database
|
||||
object. To generate the script, select the checkboxes of the database
|
||||
objects in the object comparison panel and then click on the *Generate Script*
|
||||
button in the upper-right hand corner of the object comparison panel.
|
||||
|
||||
.. image:: images/schema_diff_generate_script.png
|
||||
:alt: Schema diff generate script
|
||||
:align: center
|
||||
|
||||
Select the schema objects and click on the *Generate Script*
|
||||
Select the database objects and click on the *Generate Script*
|
||||
button to open the *Query Tool* in a new tab, with the difference
|
||||
in the SQL statement displayed in the *Query Editor*.
|
||||
|
||||
If you have clicked on the schema object to check the difference
|
||||
If you have clicked on the database object to check the difference
|
||||
generated in the *DDL Comparison* Panel, and you have not selected the
|
||||
checkbox of the schema object, PEM will open the *Query Tool* in a new
|
||||
checkbox of the database object, pgAdmin will open the *Query Tool* in a new
|
||||
tab, with the differences in the SQL statements displayed in the *Query Editor*.
|
||||
|
||||
You can also use the *Copy* button to copy the difference generated in
|
||||
@@ -133,4 +125,4 @@ the *DDL Comparison* panel.
|
||||
:alt: Schema diff generate script query editor
|
||||
:align: center
|
||||
|
||||
Apply the SQL Statement in the target schema to synchronize the schemas.
|
||||
Apply the SQL Statement in the target database to synchronize the databases.
|
||||
@@ -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
|
||||
|
||||
@@ -8,6 +8,15 @@ pgAdmin may be deployed as a web application by configuring the app to run in
|
||||
server mode and then deploying it either behind a webserver running as a reverse
|
||||
proxy, or using the WSGI interface.
|
||||
|
||||
When deployed in server mode, there are two notable differences for users:
|
||||
|
||||
* Users must login before they can use pgAdmin. An initial superuser account
|
||||
is created when server mode is initialised, and this user can add additional
|
||||
superusers and non-superusers as required.
|
||||
* File storage is restricted to a virtual root directory for each individual
|
||||
user under the directory configured using the ``STORAGE_DIR`` configuration
|
||||
parameter. Users do not have access to the complete filesystem of the server.
|
||||
|
||||
The following instructions demonstrate how pgAdmin may be run as a WSGI
|
||||
application under ``Apache HTTPD``, using ``mod_wsgi``, standalone using ``uWSGI``
|
||||
or ``Gunicorn``, or under ``NGINX`` using using ``uWSGI`` or ``Gunicorn``.
|
||||
|
||||
@@ -16,15 +16,31 @@ Use the fields in the *General* tab to identify the server:
|
||||
|
||||
* Use the *Name* field to add a descriptive name for the server; the name
|
||||
specified will be displayed in the *Browser* tree control.
|
||||
|
||||
* Use the drop-down list box in the *Server group* field to select the parent
|
||||
node for the server; the server will be displayed in the *Browser* tree
|
||||
control within the specified group.
|
||||
|
||||
* Use the color-picker in the *Background* field to specify the background
|
||||
color for the server.
|
||||
|
||||
* Use the color-picker in the *Foreground* field to specify the foreground
|
||||
color for the server.
|
||||
|
||||
* If the *Connect now?* checkbox is checked, the client will attempt a
|
||||
connection to the server upon completion of the dialog; this is the default
|
||||
|
||||
* If the *Shared with all?* switch is moved to *Yes* then that server can be
|
||||
shared with all the other users. This option is available only to admin users. For more information on users see :ref:`User Management Dialog <user_management>`. The users can access the shared servers with some restritctions. The Users accessing the shared servers cannot do the following operations on the shared servers:
|
||||
|
||||
* Create a server
|
||||
* Delete the server
|
||||
* Rename the server
|
||||
* Rename the group server
|
||||
* Change of host, port, and maintenance database
|
||||
|
||||
Please note that once the server is shared, it's icon is changed in the browser tree.
|
||||
|
||||
* Provide a comment about the server in the *Comments* field.
|
||||
|
||||
Click the *Connection* tab to continue.
|
||||
@@ -183,4 +199,4 @@ Use the fields in the *Advanced* tab to configure a connection:
|
||||
|
||||
.. toctree::
|
||||
|
||||
clear_saved_passwords
|
||||
clear_saved_passwords
|
||||
@@ -7,7 +7,7 @@
|
||||
Use the *Table* dialog to create or modify a table.
|
||||
|
||||
The *Table* dialog organizes the development of a table through the following
|
||||
dialog tabs: *General*, *Columns*, *Constraints*, *Advanced*, *Parameter*, and
|
||||
dialog tabs: *General*, *Columns*, *Constraints*, *Advanced*, *Parition*, *Parameter*, and
|
||||
*Security*. The *SQL* tab displays the SQL code generated by dialog selections.
|
||||
|
||||
.. image:: images/table_general.png
|
||||
@@ -389,6 +389,8 @@ Click the *Advanced* tab to continue.
|
||||
|
||||
Use the fields in the *Advanced* tab to define advanced features for the table:
|
||||
|
||||
* Move the *RLS Policy?* switch to the *Yes* position to enable the Row Level Security.
|
||||
* Move the *Force RLS Policy?* to the *Yes* position to force the policy on the owner of the table.
|
||||
* Use the drop-down listbox next to *Of type* to copy the table structure from
|
||||
the specified composite type. Please note that a typed table will be dropped
|
||||
if the type is dropped (with DROP TYPE ... CASCADE).
|
||||
@@ -485,10 +487,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.
|
||||
|
||||
@@ -22,10 +22,6 @@ div.body {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
div.related a {
|
||||
color: #295C85;
|
||||
}
|
||||
|
||||
div.related a:hover {
|
||||
color: #ebeef3 !important;
|
||||
text-decoration: underline !important;
|
||||
@@ -287,23 +283,19 @@ div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points {
|
||||
padding-right: 0px;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
margin: 10px 10px 10px 0px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul li.toctree-l1 a cite {
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-weight: 400;
|
||||
color: #295C85;
|
||||
font-family: Roboto, Helvetica Neue, -apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
border:none;
|
||||
padding:0px;
|
||||
background-color: #f5f7f9;
|
||||
|
||||
@@ -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
|
||||
@@ -35,7 +35,7 @@ cat << EOF > "${SERVERROOT}/DEBIAN/control"
|
||||
Package: ${APP_NAME}-server
|
||||
Version: ${APP_LONG_VERSION}
|
||||
Architecture: ${OS_ARCH}
|
||||
Depends: python3, libpq5
|
||||
Depends: python3, libpq5 (>= 11.0)
|
||||
Recommends: postgresql-client | postgresql-client-12 | postgresql-client-11 | postgresql-client-10
|
||||
Maintainer: pgAdmin Development Team <pgadmin-hackers@postgresql.org>
|
||||
Description: The core server package for pgAdmin. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
@@ -106,3 +106,10 @@ EOF
|
||||
|
||||
# Build the Debian meta package
|
||||
fakeroot dpkg-deb --build "${METAROOT}" "${DISTROOT}/${APP_NAME}_${APP_LONG_VERSION}_all.deb"
|
||||
|
||||
# Get the libpq package
|
||||
pushd ${DISTROOT} 1> /dev/null
|
||||
apt-get download libpq5
|
||||
popd 1> /dev/null
|
||||
|
||||
echo "Completed. DEBs created in ${DISTROOT}."
|
||||
@@ -6,11 +6,16 @@ if [ "$EUID" -ne 0 ]
|
||||
fi
|
||||
|
||||
echo "Installing system pre-requisites..."
|
||||
apt install -y curl apt-transport-https ca-certificates
|
||||
apt install -y curl apt-transport-https ca-certificates gnupg
|
||||
|
||||
echo "Removing yarn (which may not be the package we expect)..."
|
||||
dpkg -r yarn
|
||||
|
||||
# PostgreSQL
|
||||
echo "Setting up the PostgreSQL repo..."
|
||||
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
||||
|
||||
# Node repo
|
||||
echo "Setting up the NodeJS repo..."
|
||||
curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||
@@ -25,5 +30,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
|
||||
|
||||
@@ -53,6 +53,10 @@ _create_python_virtualenv() {
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
|
||||
# Make sure we have the wheel package present
|
||||
pip3 install wheel
|
||||
|
||||
# Install the requirements
|
||||
pip3 install --no-cache-dir --no-binary psycopg2 -r ${SOURCEDIR}/requirements.txt
|
||||
|
||||
# Figure out some paths for use when completing the venv
|
||||
@@ -107,9 +111,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"
|
||||
@@ -139,10 +143,10 @@ _copy_code() {
|
||||
# Remove any TCL-related files that may cause us problems
|
||||
find "${SERVERROOT}/usr/${APP_NAME}/venv/" -name "_tkinter*" -print0 | xargs -0 rm -rf
|
||||
|
||||
pushd ${SOURCEDIR}/web
|
||||
pushd ${SOURCEDIR}/web > /dev/null
|
||||
yarn install
|
||||
yarn run bundle
|
||||
popd
|
||||
popd > /dev/null
|
||||
|
||||
# copy the web directory to the bundle as it is required by runtime
|
||||
cp -r "${SOURCEDIR}/web" "${SERVERROOT}/usr/${APP_NAME}/web/"
|
||||
@@ -154,6 +158,10 @@ _copy_code() {
|
||||
find . -name "feature_tests" -type d -print0 | xargs -0 rm -rf
|
||||
find . -name "__pycache__" -type d -print0 | xargs -0 rm -rf
|
||||
|
||||
# License files
|
||||
cp "${SOURCEDIR}/LICENSE" "${SERVERROOT}/usr/${APP_NAME}/"
|
||||
cp "${SOURCEDIR}/DEPENDENCIES" "${SERVERROOT}/usr/${APP_NAME}/"
|
||||
|
||||
# Web setup script
|
||||
mkdir -p "${WEBROOT}/usr/${APP_NAME}/bin/"
|
||||
cp "${SOURCEDIR}/pkg/linux/setup-web.sh" "${WEBROOT}/usr/${APP_NAME}/bin/"
|
||||
|
||||
@@ -9,16 +9,28 @@ if [ "$EUID" -ne 0 ]
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$#" -ne 0 ]] && ([[ "$#" -eq 1 ]] && [[ "$1" != "--yes" ]]); then
|
||||
echo "Usage: $0 [--yes]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the distro
|
||||
IS_REDHAT=0
|
||||
IS_DEBIAN=0
|
||||
UNAME=$(uname -a)
|
||||
|
||||
# Is this an automated install?
|
||||
AUTOMATED=0
|
||||
if [ "$#" -eq 1 ]; then
|
||||
AUTOMATED=1
|
||||
echo "Running in non-interactive mode..."
|
||||
fi
|
||||
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
IS_REDHAT=1
|
||||
APACHE=httpd
|
||||
echo "Setting up pgAdmin 4 in web mode on a Redhat platform..."
|
||||
elif [[ ${UNAME} =~ "Ubuntu" ]] || [[ ${UNAME} =~ "debian" ]]; then
|
||||
elif [[ ${UNAME} =~ "Ubuntu" ]] || [[ ${UNAME} =~ "Debian" ]]; then
|
||||
IS_DEBIAN=1
|
||||
APACHE=apache2
|
||||
echo "Setting up pgAdmin 4 in web mode on a Debian platform..."
|
||||
@@ -47,22 +59,33 @@ 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
|
||||
if [ ${IS_DEBIAN} == 1 ]; then
|
||||
read -p "We can now configure the Apache Web server for you. This involves enabling the wsgi module and configuring the pgAdmin 4 application to mount at /pgadmin4. Do you wish to continue (y/n)? " RESPONSE
|
||||
if [ ${AUTOMATED} == 1 ]; then
|
||||
RESPONSE=Y
|
||||
else
|
||||
read -p "We can now configure the Apache Web server for you. This involves enabling the wsgi module and configuring the pgAdmin 4 application to mount at /pgadmin4. Do you wish to continue (y/n)? " RESPONSE
|
||||
fi
|
||||
|
||||
case ${RESPONSE} in
|
||||
y|Y )
|
||||
a2enmod wsgi 1> /dev/null
|
||||
a2enconf pgadmin4 1> /dev/null
|
||||
;;
|
||||
# Debian uses a different path to Ubuntu
|
||||
if [[ ${UNAME} =~ "Debian" ]]; then
|
||||
/sbin/a2enmod wsgi 1> /dev/null
|
||||
/sbin/a2enconf pgadmin4 1> /dev/null
|
||||
else
|
||||
/usr/sbin/a2enmod wsgi 1> /dev/null
|
||||
/usr/sbin/a2enconf pgadmin4 1> /dev/null
|
||||
fi
|
||||
;;
|
||||
* )
|
||||
exit 1;;
|
||||
esac
|
||||
@@ -70,20 +93,30 @@ fi
|
||||
|
||||
APACHE_STATUS=`ps cax | grep ${APACHE}`
|
||||
if [ $? -eq 0 ]; then
|
||||
read -p "The Apache web server is running. A restart is required for the pgAdmin 4 installation to complete. Would you like to continue (y/n)? " RESPONSE
|
||||
if [ ${AUTOMATED} == 1 ]; then
|
||||
RESPONSE=Y
|
||||
else
|
||||
read -p "The Apache web server is running and must be restarted for the pgAdmin 4 installation to complete. Continue (y/n)? " RESPONSE
|
||||
fi
|
||||
|
||||
case ${RESPONSE} in
|
||||
y|Y )
|
||||
systemctl restart ${APACHE}
|
||||
if [ $? != 0 ]; then
|
||||
echo "Error restarting ${APACHE}. Please check the systemd logs"
|
||||
else
|
||||
echo "Apache successfully restarted. You can now start using pgAdmin 4 in web mode"
|
||||
echo "Apache successfully restarted. You can now start using pgAdmin 4 in web mode at http://127.0.0.1/pgadmin4"
|
||||
fi;;
|
||||
* )
|
||||
exit 1;;
|
||||
esac
|
||||
else
|
||||
read -p "The Apache web server is not running. We can enable and start the web server for you to finish pgAdmin 4 installation. Would you like to continue (y/n)? " RESPONSE
|
||||
if [ ${AUTOMATED} == 1 ]; then
|
||||
RESPONSE=Y
|
||||
else
|
||||
read -p "The Apache web server is not running. We can enable and start the web server for you to finish pgAdmin 4 installation. Continue (y/n)? " RESPONSE
|
||||
fi
|
||||
|
||||
case ${RESPONSE} in
|
||||
y|Y )
|
||||
systemctl enable ${APACHE}
|
||||
@@ -97,7 +130,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,386 @@
|
||||
_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
|
||||
|
||||
# License files
|
||||
cp -r ${SOURCE_DIR}/LICENSE "${BUNDLE_DIR}/Contents/"
|
||||
cp -r ${SOURCE_DIR}/DEPENDENCIES "${BUNDLE_DIR}/Contents/"
|
||||
|
||||
# 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.
|
||||
}
|
||||
@@ -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
|
||||
@@ -45,9 +45,9 @@ def mktemp(dir=None, suffix=''):
|
||||
|
||||
|
||||
def main(options, args):
|
||||
dmgFile, license = args
|
||||
with mktemp('.') as tmpFile:
|
||||
with open(tmpFile, 'w') as f:
|
||||
dmg_file, license_file = args
|
||||
with mktemp('.') as tmp_file:
|
||||
with open(tmp_file, 'w') as f:
|
||||
f.write("""data 'TMPL' (128, "LPic") {
|
||||
$"1344 6566 6175 6C74 204C 616E 6775 6167"
|
||||
$"6520 4944 4457 5244 0543 6F75 6E74 4F43"
|
||||
@@ -90,8 +90,9 @@ data 'STR#' (5002, "English") {
|
||||
$"2C20 7072 6573 7320 2244 6973 6167 7265"
|
||||
$"6522 2E"
|
||||
};\n\n""")
|
||||
with open(license, 'r') as lines:
|
||||
kind = 'RTF ' if license.lower().endswith('.rtf') else 'TEXT'
|
||||
with open(license_file, 'r') as lines:
|
||||
kind = 'RTF ' if license_file.lower().endswith('.rtf') \
|
||||
else 'TEXT'
|
||||
f.write('data \'%s\' (5000, "English") {\n' % kind)
|
||||
|
||||
def escape(s):
|
||||
@@ -110,24 +111,24 @@ data 'STR#' (5002, "English") {
|
||||
$"0100 0000 0000 0000 0000 0000 002A 000C"
|
||||
$"0009 0014 0000 0000 0000 0000 0000"
|
||||
};\n""")
|
||||
os.system('hdiutil unflatten -quiet "%s"' % dmgFile)
|
||||
os.system('hdiutil unflatten -quiet "%s"' % dmg_file)
|
||||
ret = os.system('%s -a %s -o "%s"' %
|
||||
(options.rez, tmpFile, dmgFile))
|
||||
os.system('hdiutil flatten -quiet "%s"' % dmgFile)
|
||||
(options.rez, tmp_file, dmg_file))
|
||||
os.system('hdiutil flatten -quiet "%s"' % dmg_file)
|
||||
if options.compression is not None:
|
||||
os.system('cp %s %s.temp.dmg' % (dmgFile, dmgFile))
|
||||
os.remove(dmgFile)
|
||||
os.system('cp %s %s.temp.dmg' % (dmg_file, dmg_file))
|
||||
os.remove(dmg_file)
|
||||
if options.compression == "bz2":
|
||||
os.system('hdiutil convert %s.temp.dmg -format UDBZ -o %s' %
|
||||
(dmgFile, dmgFile))
|
||||
(dmg_file, dmg_file))
|
||||
elif options.compression == "gz":
|
||||
os.system('hdiutil convert %s.temp.dmg -format ' % dmgFile +
|
||||
'UDZO -imagekey zlib-devel=9 -o %s' % dmgFile)
|
||||
os.remove('%s.temp.dmg' % dmgFile)
|
||||
os.system('hdiutil convert %s.temp.dmg -format ' % dmg_file +
|
||||
'UDZO -imagekey zlib-devel=9 -o %s' % dmg_file)
|
||||
os.remove('%s.temp.dmg' % dmg_file)
|
||||
if ret == 0:
|
||||
print("Successfully added license to '%s'" % dmgFile)
|
||||
print("Successfully added license to '%s'" % dmg_file)
|
||||
else:
|
||||
print("Failed to add license to '%s'" % dmgFile)
|
||||
print("Failed to add license to '%s'" % dmg_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ do
|
||||
done
|
||||
|
||||
cd ../
|
||||
for FILE in LICENSE README libraries.txt
|
||||
for FILE in LICENSE DEPENDENCIES README
|
||||
do
|
||||
echo Adding ${FILE}
|
||||
# We use tar here to preserve the path, as Mac (for example) doesn't support cp --parents
|
||||
@@ -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
|
||||
|
||||
@@ -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-----
|
||||
@@ -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
|
||||
@@ -11,6 +11,9 @@ OS_VERSION=$(cat /etc/os-release | grep "^VERSION_ID=" | awk -F "=" '{ print $2
|
||||
OS_NAME=$(cat /etc/os-release | grep "^ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
|
||||
OS_ARCH=$(arch)
|
||||
|
||||
# Make sure we get the right libpq
|
||||
export PATH=/usr/pgsql-12/bin:$PATH
|
||||
|
||||
# Common Linux build functions
|
||||
source pkg/linux/build-functions.sh
|
||||
|
||||
@@ -48,12 +51,8 @@ Release: 1%{?dist}
|
||||
Summary: The core server package for pgAdmin.
|
||||
License: PostgreSQL
|
||||
URL: https://www.pgadmin.org/
|
||||
%if 0%{?rhel} && 0%{?rhel} != 7
|
||||
Requires: python3, libpq
|
||||
Recommends: postgresql
|
||||
%else
|
||||
Requires: python3, postgresql
|
||||
%endif
|
||||
|
||||
Requires: python3, postgresql-libs >= 11
|
||||
|
||||
%description
|
||||
The core server package for pgAdmin. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
|
||||
@@ -204,6 +203,9 @@ if [ ${OS_VERSION} == 7 ]; then
|
||||
rpmbuild -bb "${SOURCEDIR}/pkg/redhat/pgadmin4-python-mod_wsgi.spec"
|
||||
fi
|
||||
|
||||
# Get the libpq we need
|
||||
yumdownloader --downloadonly --destdir=$DISTROOT postgresql12-libs
|
||||
|
||||
#
|
||||
# Get the results!
|
||||
#
|
||||
@@ -212,3 +214,5 @@ cp ${HOME}/rpmbuild/RPMS/noarch/${APP_NAME}-*${APP_LONG_VERSION}-*.noarch.rpm "$
|
||||
if [ ${OS_VERSION} == 7 ]; then
|
||||
cp ${HOME}/rpmbuild/RPMS/${OS_ARCH}/pgadmin4-python3-mod_wsgi-4.7.1-2.el7.x86_64.rpm "${DISTROOT}/"
|
||||
fi
|
||||
|
||||
echo "Completed. RPMs created in ${DISTROOT}."
|
||||
@@ -0,0 +1,110 @@
|
||||
#!/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"
|
||||
echo gpgkey=file:///etc/pki/rpm-gpg/PGADMIN_PKG_KEY >> "${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
|
||||
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}/"
|
||||
@@ -8,9 +8,18 @@ fi
|
||||
OS_VERSION=$(cat /etc/os-release | grep "^VERSION_ID=" | awk -F "=" '{ print $2 }' | sed 's/"//g')
|
||||
|
||||
# EPEL & other repos
|
||||
yum -y install centos-release-scl
|
||||
yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-${OS_VERSION}.noarch.rpm
|
||||
if [ ${OS_VERSION} == 8 ]; then
|
||||
yum config-manager --enable PowerTools AppStream BaseOS *epel
|
||||
dnf -qy module disable postgresql
|
||||
fi
|
||||
|
||||
# PostgreSQL repo
|
||||
if [ ${OS_VERSION} == 7 ] || [ ${OS_VERSION} == 8 ]; then
|
||||
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm
|
||||
else
|
||||
yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/F-${OS_VERSION}-x86_64/pgdg-fedora-repo-latest.noarch.rpm
|
||||
fi
|
||||
|
||||
# Node repo
|
||||
@@ -26,28 +35,37 @@ echo "Installing build pre-requisites..."
|
||||
yum groupinstall -y "Development Tools"
|
||||
|
||||
if [ ${OS_VERSION} == 7 ]; then
|
||||
yum install -y expect fakeroot httpd-devel qt5-qtbase-devel postgresql-devel python3-devel nodejs yarn rpm-build rpm-sign
|
||||
yum install -y expect fakeroot httpd-devel qt5-qtbase-devel postgresql12-devel python3-devel nodejs yarn rpm-build rpm-sign yum-utils
|
||||
pip3 install sphinx
|
||||
else
|
||||
yum install -y expect fakeroot qt5-qtbase-devel libpq-devel python3-devel python3-sphinx nodejs yarn rpm-build rpm-sign
|
||||
yum install -y expect fakeroot qt5-qtbase-devel postgresql12-devel python3-devel python3-sphinx nodejs yarn rpm-build rpm-sign yum-utils
|
||||
fi
|
||||
|
||||
# Setup RPM macros for signing
|
||||
echo "Please add the following macros to ~/.rpmmacros for the user that will sign the RPMs if required:"
|
||||
echo
|
||||
cat << EOF
|
||||
if [ ${OS_VERSION} == 7 ]; then
|
||||
cat << EOF
|
||||
# Macros for signing RPMs.
|
||||
|
||||
%_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}'
|
||||
%__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}
|
||||
EOF
|
||||
else
|
||||
cat << EOF
|
||||
# Macros for signing RPMs.
|
||||
|
||||
%_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}
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ do
|
||||
tar cf - ${FILE} | (cd src-build/${TARBALL_NAME}; tar xf -)
|
||||
done
|
||||
|
||||
pushd web
|
||||
pushd web > /dev/null
|
||||
yarn install
|
||||
yarn run bundle
|
||||
|
||||
@@ -78,7 +78,7 @@ pushd web
|
||||
echo Adding ${FILE}
|
||||
tar cf - ${FILE} | (cd ../src-build/${TARBALL_NAME}/web; tar xf -)
|
||||
done
|
||||
popd
|
||||
popd > /dev/null
|
||||
|
||||
# Create the tarball
|
||||
echo Creating tarball...
|
||||
|
||||
@@ -1,46 +1,155 @@
|
||||
Building pgAdmin windows installer on windows
|
||||
=================================
|
||||
These notes describe how to setup a Windows development/build environment for
|
||||
pgAdmin. They assume a 64bit build is required; adjustments will be required for
|
||||
a 32bit build.
|
||||
|
||||
To generate a pgAdmin 4 installer for Windows bit, the following packages must be installed:
|
||||
Installing build requirements
|
||||
=============================
|
||||
|
||||
1. Python installation
|
||||
- Python 2.7 or 3.4+ or above from https://www.python.org/
|
||||
1) Install Qt 5.14.2: https://www.qt.io/download-qt-installer
|
||||
|
||||
2. QT installation
|
||||
- Qt 4.6 through 5.5 from http://www.qt.io/
|
||||
Use the MSVC++ 2017 64bit option.
|
||||
|
||||
3. PostgreSQL installation
|
||||
- PostgreSQL 9.1 or above from http://www.postgresql.org/
|
||||
2) Install Visual Studio 2017 Pro: https://my.visualstudio.com/Downloads?q=Visual%20Studio%202017
|
||||
|
||||
4. Inno Setup Installer (unicode)
|
||||
- 5.0 and above from http://www.jrsoftware.org/isdl.php
|
||||
Choose the Desktop development with C++ option.
|
||||
|
||||
5. Microsoft visual studio (2008 and above)
|
||||
3) Install Chocolatey: https://chocolatey.org/install#individual
|
||||
|
||||
Building: Depending upon the archicture of the OS(x86|amd64) set then environment variables.
|
||||
4) Install various command line tools:
|
||||
|
||||
1. Set the PYTHON environment variable to the Python root installation directory, e.g. for x86
|
||||
choco install -y bzip2 cmake diffutils gzip git innosetup nodejs-lts python strawberryperl wget yarn
|
||||
|
||||
SET "PYTHON_HOME=C:\Python27"
|
||||
SET "PYTHON_DLL=C:\Windows\System32\python27.dll"
|
||||
5) Upgrade pip (this may give a permissions error that can be ignored):
|
||||
|
||||
2. Set the QTDIR environment variable to the QT root installation directory, e.g. for x86
|
||||
pip install --upgrade pip
|
||||
|
||||
SET "QTDIR=C:\Qt\Qt5.5.1\5.5\msvc2013"
|
||||
6) Install virtualenv
|
||||
|
||||
3. Set the PGDIR environment variable to the PostgreSQL installation directory, e.g. for x86
|
||||
pip install virtualenv
|
||||
|
||||
SET "PGDIR=C:\Program Files\PostgreSQL\9.5"
|
||||
Building dependencies
|
||||
=====================
|
||||
|
||||
4. Set the Inno Setup Installer environment variable to the Inno root installation directory, e.g. for x86
|
||||
The following steps should be run from a Visual Studio 2017 64bit command
|
||||
prompt.
|
||||
|
||||
SET "INNOTOOL=C:\Program Files\Inno Setup 5"
|
||||
1) Create a directory for the dependencies:
|
||||
|
||||
5. Set the Miscrosoft Visual studio environment variable to the Visual studio root installation directory, e.g. for x86
|
||||
mkdir c:\build64
|
||||
|
||||
SET "VCDIR=C:\Program Files\Microsoft Visual Studio 12.0\VC"
|
||||
2) Download the zlib source code, unpack, and build it:
|
||||
|
||||
6. To build, go to pgAdmin4 source root directory and execute "Make.bat x86|amd64". Based on x86|amd64, 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 windows installer x86|amd64 in ./dist directory
|
||||
wget https://zlib.net/zlib-1.2.11.tar.gz
|
||||
tar -zxvf zlib-1.2.11.tar.gz
|
||||
cd zlib-1.2.11
|
||||
cmake -DCMAKE_INSTALL_PREFIX=C:/build64/zlib -G "Visual Studio 15 2017 Win64" .
|
||||
msbuild RUN_TESTS.vcxproj /p:Configuration=Release
|
||||
msbuild INSTALL.vcxproj /p:Configuration=Release
|
||||
copy C:\build64\zlib\lib\zlib.lib C:\build64\zlib\lib\zdll.lib
|
||||
|
||||
3) Download the OpenSSL source code, unpack and build it:
|
||||
|
||||
wget https://www.openssl.org/source/openssl-1.1.1g.tar.gz
|
||||
tar -zxvf openssl-1.1.1g.tar.gz
|
||||
cd openssl-1.1.1g
|
||||
perl Configure VC-WIN64A no-asm --prefix=C:\build64\openssl no-ssl2 no-ssl3 no-comp
|
||||
nmake
|
||||
nmake test
|
||||
nmake install
|
||||
|
||||
Note that if you are not working in an administrative account, you may need to
|
||||
create and give your regular account appropriate permissions to write/modify
|
||||
files in C:\Program Files\Common Files\SSL. This is the default directory used
|
||||
for the OPENSSLDIR, and should not be changed to a directory that un-privileged
|
||||
users could potentially write to.
|
||||
|
||||
4) Download the PostgreSQL source code, unpack and build it:
|
||||
|
||||
wget https://ftp.postgresql.org/pub/source/v12.3/postgresql-12.3.tar.bz2
|
||||
tar -zxvf postgresql-12.3.tar.gz
|
||||
cd postgresql-12.3\src\tools\msvc
|
||||
|
||||
>> config.pl echo # Configuration arguments for vcbuild.
|
||||
>> config.pl echo use strict;
|
||||
>> config.pl echo use warnings;
|
||||
>> config.pl echo.
|
||||
>> config.pl echo our $config = {
|
||||
>> config.pl echo asserts =^> 0, # --enable-cassert
|
||||
>> config.pl echo ldap =^> 1, # --with-ldap
|
||||
>> config.pl echo extraver =^> undef, # --with-extra-version=^<string^>
|
||||
>> config.pl echo gss =^> undef, # --with-gssapi=^<path^>
|
||||
>> config.pl echo icu =^> undef, # --with-icu=^<path^>
|
||||
>> config.pl echo nls =^> undef, # --enable-nls=^<path^>
|
||||
>> config.pl echo tap_tests =^> undef, # --enable-tap-tests
|
||||
>> config.pl echo tcl =^> undef, # --with-tcl=^<path^>
|
||||
>> config.pl echo perl =^> undef, # --with-perl
|
||||
>> config.pl echo python =^> undef, # --with-python=^<path^>
|
||||
>> config.pl echo openssl =^> 'C:\build64\openssl', # --with-openssl=^<path^>
|
||||
>> config.pl echo uuid =^> undef, # --with-ossp-uuid
|
||||
>> config.pl echo xml =^> undef, # --with-libxml=^<path^>
|
||||
>> config.pl echo xslt =^> undef, # --with-libxslt=^<path^>
|
||||
>> config.pl echo iconv =^> undef, # (not in configure, path to iconv)
|
||||
>> config.pl echo zlib =^> 'C:\build64\zlib' # --with-zlib=^<path^>
|
||||
>> config.pl echo };
|
||||
>> config.pl echo.
|
||||
>> config.pl echo 1;
|
||||
|
||||
>> buildenv.pl echo $ENV{PATH} = "C:\\build64\\openssl\\bin;C:\\build64\\zlib\\bin;$ENV{PATH}";
|
||||
|
||||
perl build.pl Release
|
||||
perl vcregress.pl check
|
||||
perl install.pl C:\build64\pgsql
|
||||
copy C:\build64\zlib\bin\zlib.dll C:\build64\pgsql\bin"
|
||||
copy C:\build64\openssl\bin\libssl-1_1-x64.dll C:\build64\pgsql\bin"
|
||||
copy C:\build64\openssl\bin\libcrypto-1_1-x64.dll C:\build64\pgsql\bin"
|
||||
|
||||
Setting up a dev environment
|
||||
============================
|
||||
|
||||
This section describes the steps to setup and run pgAdmin for the first time in
|
||||
a development environment. You do not need to complete this section if you just
|
||||
want to build an installer.
|
||||
|
||||
1) Check out the source code:
|
||||
|
||||
git clone https://git.postgresql.org/git/pgadmin4.git
|
||||
|
||||
2) Install and build the JS dependencies
|
||||
|
||||
cd pgadmin4\web
|
||||
yarn install
|
||||
yarn run bundle
|
||||
|
||||
3) Create a virtual env
|
||||
|
||||
cd pgadmin4
|
||||
python -m venv venv
|
||||
pip install -r web\regression\requirements.txt
|
||||
pip install sphinx
|
||||
|
||||
You should now be able to run the pgAdmin Python application, or build the
|
||||
desktop runtime.
|
||||
|
||||
Building an installer
|
||||
=====================
|
||||
|
||||
1) Set the required environment variables, either system-wide, or in a Visual
|
||||
Studio 2017 64bit command prompt. Note that the examples shown below are the
|
||||
defaults for the build system, so if they match your requirements you don't
|
||||
need to set them:
|
||||
|
||||
SET "PGADMIN_POSTGRES_DIR=C:\Program Files\PostgreSQL\12"
|
||||
SET "PGADMIN_PYTHON_DIR=C:\Python38"
|
||||
SET "PGADMIN_QT_DIR=C:\Qt\5.14.2\msvc2017_64"
|
||||
SET "PGADMIN_INNOTOOL_DIR=C:\Program Files (x86)\Inno Setup 6"
|
||||
SET "PGADMIN_SIGNTOOL_DIR=C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64"
|
||||
SET "PGADMIN_VCREDIST_DIR=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Redist\MSVC\14.16.27012"
|
||||
|
||||
2) Run:
|
||||
|
||||
make
|
||||
|
||||
If you have a code signing certificate, this will automatically be used if
|
||||
found in the Windows Certificate Store to sign the installer.
|
||||
|
||||
3) Find the completed installer in the dist/ subdirectory of your source tree.
|
||||
@@ -8,6 +8,8 @@
|
||||
#define MyAppArchitecturesMode MYAPP_ARCHITECTURESMODE
|
||||
#define MyAppVCDist MYAPP_VCDIST
|
||||
#define MyAppInvalidPath "Please provide a valid path."
|
||||
#define MyAppErrorMsgIsWin32 "You already have a 32 bit installation of pgAdmin 4. Please uninstall this before installing the 64 bit version."
|
||||
#define MyAppErrorMsgIsWin64 "You already have a 64 bit installation of pgAdmin 4. Please uninstall this before installing the 32 bit version."
|
||||
|
||||
[Setup]
|
||||
AppId={#MyAppName}{#MyAppVersion}
|
||||
@@ -35,7 +37,7 @@ AllowNoIcons=yes
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
;This section will override the standered error message by default which is called internally and we don't have a controll over this.
|
||||
;This section will override the standard error message by default which is called internally and we don't have a control over this.
|
||||
[Messages]
|
||||
InvalidPath={#MyAppInvalidPath}
|
||||
|
||||
@@ -170,30 +172,75 @@ begin
|
||||
Result := Ret;
|
||||
end;
|
||||
|
||||
// Find current version before installation
|
||||
function InitializeSetup: Boolean;
|
||||
function CheckPgAdminAlreadyInstalled: Boolean;
|
||||
var
|
||||
Version: String;
|
||||
InstallationFound: Boolean;
|
||||
begin
|
||||
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', 'Version') then
|
||||
InstallationFound := False;
|
||||
// Check the installation mode 64 or 32 bit of installer
|
||||
if Is64BitInstallMode then
|
||||
begin
|
||||
UpgradeMode := True;
|
||||
RegQueryStringValue(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version);
|
||||
if CompareVersions(Version, '{#MyAppFullVersion}') = 1 then
|
||||
|
||||
// Check if pgAdmin 32 bit is already installed
|
||||
RegQueryStringValue(HKLM32,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version);
|
||||
|
||||
// If version is found then shouldn't install 64bit - abort
|
||||
if Length(Version) > 0 then
|
||||
begin
|
||||
MsgBox(ExpandConstant('{cm:NewerVersionExists}' + '(v' + Version + ') is already installed' ), mbInformation, MB_OK);
|
||||
Result := False;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := True;
|
||||
MsgBox(ExpandConstant('{#MyAppErrorMsgIsWin32}'), mbCriticalError, MB_OK);
|
||||
Result := False;
|
||||
InstallationFound := True;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := True;
|
||||
UpgradeMode := False;
|
||||
// Suppose system is running a 32-bit version of Windows then no need to check HKLM64 in RegQueryStringValue
|
||||
// So IsWin64 - will make sure its should only execute on 64-bit veersion of windows.
|
||||
if IsWin64 then
|
||||
begin
|
||||
// Check if pgAdmin 64 bit is already installed
|
||||
RegQueryStringValue(HKLM64,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version);
|
||||
|
||||
// If version is found the shouldn't install 32bit - abort
|
||||
if Length(Version) > 0 then
|
||||
begin
|
||||
MsgBox(ExpandConstant('{#MyAppErrorMsgIsWin64}'), mbCriticalError, MB_OK);
|
||||
Result := False;
|
||||
InstallationFound := True;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
if not (InstallationFound) then
|
||||
begin
|
||||
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', 'Version') then
|
||||
begin
|
||||
UpgradeMode := True;
|
||||
RegQueryStringValue(HKEY_LOCAL_MACHINE,'Software\{#MyAppName}\{#MyAppVersion}', 'Version', Version);
|
||||
if CompareVersions(Version, '{#MyAppFullVersion}') = 1 then
|
||||
begin
|
||||
MsgBox(ExpandConstant('{cm:NewerVersionExists}' + '(v' + Version + ') is already installed' ), mbInformation, MB_OK);
|
||||
Result := False;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
if ( not (InstallationFound) and not (UpgradeMode) ) then
|
||||
begin
|
||||
// This is required as it will be passed on to the InitializeSetup function
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Find current version before installation
|
||||
function InitializeSetup: Boolean;
|
||||
begin
|
||||
Result := CheckPgAdminAlreadyInstalled;
|
||||
end;
|
||||
|
||||
function IsUpgradeMode(): Boolean;
|
||||
|
||||
@@ -38,5 +38,7 @@ psycopg2>=2.8
|
||||
python-dateutil>=2.8.0
|
||||
SQLAlchemy>=1.3.13
|
||||
Flask-Security-Too>=3.0.0
|
||||
sshtunnel>=0.1.4
|
||||
bcrypt<=3.1.7
|
||||
cryptography<=3.0
|
||||
sshtunnel>=0.1.5
|
||||
ldap3>=2.5.1
|
||||
@@ -9,28 +9,106 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "ConfigWindow.h"
|
||||
#include "ui_ConfigWindow.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QTcpSocket>
|
||||
#include <QtWidgets>
|
||||
|
||||
ConfigWindow::ConfigWindow(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ConfigWindow)
|
||||
QDialog(parent)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
initConfigWindow();
|
||||
}
|
||||
|
||||
ConfigWindow::~ConfigWindow()
|
||||
void ConfigWindow::initConfigWindow()
|
||||
{
|
||||
delete ui;
|
||||
ui = new Ui::ConfigWindow;
|
||||
ui->setupUi(this);
|
||||
|
||||
m_needRestart = false;
|
||||
|
||||
setConfigValues();
|
||||
}
|
||||
|
||||
void ConfigWindow::setConfigValues()
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
ui->browserCommandLineEdit->setText(settings.value("BrowserCommand").toString());
|
||||
|
||||
if(settings.value("FixedPort").toBool())
|
||||
{
|
||||
ui->chkFixedPort->setCheckState(Qt::Checked);
|
||||
ui->spinPortNumber->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->chkFixedPort->setCheckState(Qt::Unchecked);
|
||||
ui->spinPortNumber->setEnabled(false);
|
||||
}
|
||||
|
||||
ui->spinPortNumber->setValue(settings.value("PortNumber").toInt());
|
||||
|
||||
if (settings.value("OpenTabAtStartup", true).toBool())
|
||||
{
|
||||
ui->chkOpenTabAtStartup->setCheckState(Qt::Checked);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->chkOpenTabAtStartup->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
|
||||
ui->pythonPathLineEdit->setText(settings.value("PythonPath").toString());
|
||||
ui->applicationPathLineEdit->setText(settings.value("ApplicationPath").toString());
|
||||
}
|
||||
|
||||
void ConfigWindow::on_buttonBox_accepted()
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
// Save the settings, and return true if a restart is required, otherwise false.
|
||||
QString browsercommand = ui->browserCommandLineEdit->text();
|
||||
bool fixedport = ui->chkFixedPort->isChecked();
|
||||
int portnumber = ui->spinPortNumber->value();
|
||||
bool opentabatstartup = ui->chkOpenTabAtStartup->isChecked();
|
||||
QString pythonpath = ui->pythonPathLineEdit->text();
|
||||
QString applicationpath = ui->applicationPathLineEdit->text();
|
||||
|
||||
if (fixedport && (settings.value("FixedPort").toBool() != fixedport ||
|
||||
settings.value("PortNumber").toInt() != portnumber) && isPortInUse(portnumber))
|
||||
{
|
||||
QString error = QString(QWidget::tr("The specified fixed port is already in use. Please provide any other valid port."));
|
||||
QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_needRestart = (settings.value("FixedPort").toBool() != fixedport ||
|
||||
settings.value("PortNumber").toInt() != portnumber ||
|
||||
settings.value("PythonPath").toString() != pythonpath ||
|
||||
settings.value("ApplicationPath").toString() != applicationpath);
|
||||
|
||||
settings.setValue("BrowserCommand", browsercommand);
|
||||
settings.setValue("FixedPort", fixedport);
|
||||
settings.setValue("PortNumber", portnumber);
|
||||
settings.setValue("OpenTabAtStartup", opentabatstartup);
|
||||
settings.setValue("PythonPath", pythonpath);
|
||||
settings.setValue("ApplicationPath", applicationpath);
|
||||
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
emit accepted(m_needRestart);
|
||||
emit closing(true);
|
||||
|
||||
this->close();
|
||||
}
|
||||
|
||||
void ConfigWindow::on_buttonBox_rejected()
|
||||
{
|
||||
emit closing(false);
|
||||
this->close();
|
||||
}
|
||||
|
||||
@@ -42,80 +120,17 @@ void ConfigWindow::on_chkFixedPort_stateChanged(int state)
|
||||
ui->spinPortNumber->setEnabled(false);
|
||||
}
|
||||
|
||||
QString ConfigWindow::getBrowserCommand()
|
||||
bool ConfigWindow::isPortInUse(const quint16 port) const
|
||||
{
|
||||
return ui->browserCommandLineEdit->text();
|
||||
QTcpSocket socket;
|
||||
|
||||
// Bind the socket on the specified port.
|
||||
socket.bind(port, QTcpSocket::DontShareAddress);
|
||||
|
||||
// Returns the host port number of the local socket if available; otherwise returns 0
|
||||
quint16 tmpPort = socket.localPort();
|
||||
if (tmpPort == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConfigWindow::getFixedPort()
|
||||
{
|
||||
return ui->chkFixedPort->isChecked();
|
||||
}
|
||||
|
||||
int ConfigWindow::getPortNumber()
|
||||
{
|
||||
return ui->spinPortNumber->value();
|
||||
}
|
||||
|
||||
bool ConfigWindow::getOpenTabAtStartup()
|
||||
{
|
||||
return ui->chkOpenTabAtStartup->isChecked();
|
||||
}
|
||||
|
||||
QString ConfigWindow::getPythonPath()
|
||||
{
|
||||
return ui->pythonPathLineEdit->text();
|
||||
}
|
||||
|
||||
QString ConfigWindow::getApplicationPath()
|
||||
{
|
||||
return ui->applicationPathLineEdit->text();
|
||||
}
|
||||
|
||||
|
||||
void ConfigWindow::setBrowserCommand(QString command)
|
||||
{
|
||||
ui->browserCommandLineEdit->setText(command);
|
||||
}
|
||||
|
||||
void ConfigWindow::setFixedPort(bool fixedPort)
|
||||
{
|
||||
if (fixedPort)
|
||||
{
|
||||
ui->chkFixedPort->setCheckState(Qt::Checked);
|
||||
ui->spinPortNumber->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->chkFixedPort->setCheckState(Qt::Unchecked);
|
||||
ui->spinPortNumber->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigWindow::setPortNumber(int port)
|
||||
{
|
||||
ui->spinPortNumber->setValue(port);
|
||||
}
|
||||
|
||||
void ConfigWindow::setOpenTabAtStartup(bool openTabAtStartup)
|
||||
{
|
||||
if (openTabAtStartup)
|
||||
{
|
||||
ui->chkOpenTabAtStartup->setCheckState(Qt::Checked);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->chkOpenTabAtStartup->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigWindow::setPythonPath(QString path)
|
||||
{
|
||||
ui->pythonPathLineEdit->setText(path);
|
||||
}
|
||||
|
||||
void ConfigWindow::setApplicationPath(QString path)
|
||||
{
|
||||
ui->applicationPathLineEdit->setText(path);
|
||||
}
|
||||
|
||||
@@ -24,21 +24,11 @@ class ConfigWindow : public QDialog
|
||||
|
||||
public:
|
||||
explicit ConfigWindow(QWidget *parent = Q_NULLPTR);
|
||||
~ConfigWindow();
|
||||
void setConfigValues();
|
||||
|
||||
QString getBrowserCommand();
|
||||
bool getFixedPort();
|
||||
int getPortNumber();
|
||||
bool getOpenTabAtStartup();
|
||||
QString getPythonPath();
|
||||
QString getApplicationPath();
|
||||
|
||||
void setBrowserCommand(QString command);
|
||||
void setFixedPort(bool fixedPort);
|
||||
void setPortNumber(int port);
|
||||
void setOpenTabAtStartup(bool openTabAtStartup);
|
||||
void setPythonPath(QString path);
|
||||
void setApplicationPath(QString path);
|
||||
signals:
|
||||
void accepted(bool needRestart);
|
||||
void closing(bool accepted);
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
@@ -47,6 +37,10 @@ private slots:
|
||||
|
||||
private:
|
||||
Ui::ConfigWindow *ui;
|
||||
bool m_needRestart;
|
||||
|
||||
void initConfigWindow();
|
||||
bool isPortInUse(const quint16 port) const;
|
||||
};
|
||||
|
||||
#endif // CONFIGWINDOW_H
|
||||
@@ -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,12 +18,12 @@
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>975</width>
|
||||
<height>300</height>
|
||||
<width>800</width>
|
||||
<height>415</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
<string>pgAdmin 4 Configuration</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@@ -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>
|
||||
@@ -140,7 +124,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>By default the runtime uses a random port number to ensure it can always run successfully. If you need to use a predictable port number, you can set one here. Note that if the port is already in use, the application will be unable start.</string>
|
||||
<string>By default the runtime uses a random port number to ensure it can always run successfully. If you need to use a predictable port number, you can set one here. Note that if the port is already in use, the application will be unable to start.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -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>
|
||||
@@ -313,19 +303,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -365,8 +342,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 +378,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 +410,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>
|
||||
@@ -444,7 +427,7 @@
|
||||
<item>
|
||||
<widget class="QLineEdit" name="pythonPathLineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>/usr/pgadmin4/lib/python2.7;/usr/pgadmin4/lib/python2.7/site-packages</string>
|
||||
<string>/usr/pgadmin4/lib/python3.8;/usr/pgadmin4/lib/python3.8/site-packages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -458,8 +441,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 +482,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 +508,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 +539,8 @@
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>20</height>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
||||
@@ -9,30 +9,25 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "FloatingWindow.h"
|
||||
#include "ui_FloatingWindow.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
|
||||
|
||||
FloatingWindow::FloatingWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::FloatingWindow)
|
||||
QMainWindow(parent)
|
||||
{
|
||||
m_newAction = Q_NULLPTR;
|
||||
m_configAction = Q_NULLPTR;
|
||||
m_logAction = Q_NULLPTR;
|
||||
m_quitAction = Q_NULLPTR;
|
||||
m_menuActions = Q_NULLPTR;
|
||||
m_floatingWindowMenu = Q_NULLPTR;
|
||||
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
FloatingWindow::~FloatingWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool FloatingWindow::Init()
|
||||
{
|
||||
ui = new Ui::FloatingWindow;
|
||||
ui->setupUi(this);
|
||||
|
||||
// Creating Menu
|
||||
createMenu();
|
||||
|
||||
@@ -50,12 +45,13 @@ bool FloatingWindow::Init()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Create the menu
|
||||
void FloatingWindow::createMenu()
|
||||
{
|
||||
createActions();
|
||||
|
||||
m_floatingWindowMenu = menuBar()->addMenu(QString(tr("&%1")).arg(PGA_APP_NAME));
|
||||
m_floatingWindowMenu = menuBar()->addMenu(tr("&pgAdmin 4"));
|
||||
m_floatingWindowMenu->addAction(m_newAction);
|
||||
m_floatingWindowMenu->addAction(m_copyUrlAction);
|
||||
m_floatingWindowMenu->addSeparator();
|
||||
@@ -65,19 +61,24 @@ void FloatingWindow::createMenu()
|
||||
m_floatingWindowMenu->addAction(m_quitAction);
|
||||
}
|
||||
|
||||
|
||||
// Create the menu actions
|
||||
void FloatingWindow::createActions()
|
||||
{
|
||||
m_newAction = new QAction(QString(tr("&New %1 window...")).arg(PGA_APP_NAME), this);
|
||||
m_newAction = new QAction(tr("&New pgAdmin 4 window..."), this);
|
||||
m_newAction->setEnabled(false);
|
||||
connect(m_newAction, SIGNAL(triggered()), m_menuActions, SLOT(onNew()));
|
||||
|
||||
m_copyUrlAction = new QAction(tr("&Copy server URL"), this);
|
||||
m_copyUrlAction->setEnabled(false);
|
||||
connect(m_copyUrlAction, SIGNAL(triggered()), m_menuActions, SLOT(onCopyUrl()));
|
||||
|
||||
m_configAction = new QAction(tr("C&onfigure..."), this);
|
||||
m_configAction->setEnabled(false);
|
||||
connect(m_configAction, SIGNAL(triggered()), m_menuActions, SLOT(onConfig()));
|
||||
|
||||
m_logAction = new QAction(tr("&View log..."), this);
|
||||
m_logAction->setEnabled(false);
|
||||
connect(m_logAction, SIGNAL(triggered()), m_menuActions, SLOT(onLog()));
|
||||
|
||||
m_quitAction = new QAction(tr("&Shut down server"), this);
|
||||
@@ -85,12 +86,23 @@ void FloatingWindow::createActions()
|
||||
connect(m_quitAction, SIGNAL(triggered()), m_menuActions, SLOT(onQuit()));
|
||||
}
|
||||
|
||||
void FloatingWindow::enableShutdownMenu()
|
||||
|
||||
void FloatingWindow::enablePostStartOptions()
|
||||
{
|
||||
if (m_newAction != Q_NULLPTR)
|
||||
m_newAction->setEnabled(true);
|
||||
|
||||
if (m_copyUrlAction != Q_NULLPTR)
|
||||
m_copyUrlAction->setEnabled(true);
|
||||
|
||||
if (m_configAction != Q_NULLPTR)
|
||||
m_configAction->setEnabled(true);
|
||||
|
||||
if (m_logAction != Q_NULLPTR)
|
||||
m_logAction->setEnabled(true);
|
||||
|
||||
if (m_quitAction != Q_NULLPTR)
|
||||
{
|
||||
m_quitAction->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void FloatingWindow::setMenuActions(MenuActions * menuActions)
|
||||
@@ -98,6 +110,34 @@ void FloatingWindow::setMenuActions(MenuActions * menuActions)
|
||||
m_menuActions = menuActions;
|
||||
}
|
||||
|
||||
// Enable the View Log option
|
||||
void FloatingWindow::enableViewLogOption()
|
||||
{
|
||||
if (m_logAction != Q_NULLPTR)
|
||||
m_logAction->setEnabled(true);
|
||||
}
|
||||
|
||||
// Disable the View Log option
|
||||
void FloatingWindow::disableViewLogOption()
|
||||
{
|
||||
if (m_logAction != Q_NULLPTR)
|
||||
m_logAction->setEnabled(false);
|
||||
}
|
||||
|
||||
// Enable the configure option
|
||||
void FloatingWindow::enableConfigOption()
|
||||
{
|
||||
if (m_configAction != Q_NULLPTR)
|
||||
m_configAction->setEnabled(true);
|
||||
}
|
||||
|
||||
// Disable the configure option
|
||||
void FloatingWindow::disableConfigOption()
|
||||
{
|
||||
if (m_configAction != Q_NULLPTR)
|
||||
m_configAction->setEnabled(false);
|
||||
}
|
||||
|
||||
void FloatingWindow::closeEvent(QCloseEvent * event)
|
||||
{
|
||||
// Emit the signal to shut down the python server.
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef FLOATINGWINDOW_H
|
||||
#define FLOATINGWINDOW_H
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "MenuActions.h"
|
||||
|
||||
#include <QMainWindow>
|
||||
@@ -28,10 +26,13 @@ class FloatingWindow : public QMainWindow
|
||||
|
||||
public:
|
||||
explicit FloatingWindow(QWidget *parent = Q_NULLPTR);
|
||||
~FloatingWindow();
|
||||
|
||||
bool Init();
|
||||
void enableShutdownMenu();
|
||||
void enablePostStartOptions();
|
||||
void enableViewLogOption();
|
||||
void disableViewLogOption();
|
||||
void enableConfigOption();
|
||||
void disableConfigOption();
|
||||
void setMenuActions(MenuActions * menuActions);
|
||||
|
||||
private:
|
||||
@@ -41,14 +42,14 @@ private:
|
||||
void createActions();
|
||||
void closeEvent(QCloseEvent * event);
|
||||
|
||||
QAction *m_newAction;
|
||||
QAction *m_copyUrlAction;
|
||||
QAction *m_configAction;
|
||||
QAction *m_logAction;
|
||||
QAction *m_quitAction;
|
||||
QAction *m_newAction = Q_NULLPTR;
|
||||
QAction *m_copyUrlAction = Q_NULLPTR;
|
||||
QAction *m_configAction = Q_NULLPTR;
|
||||
QAction *m_logAction = Q_NULLPTR;
|
||||
QAction *m_quitAction = Q_NULLPTR;
|
||||
|
||||
QMenu *m_floatingWindowMenu;
|
||||
MenuActions *m_menuActions;
|
||||
QMenu *m_floatingWindowMenu = Q_NULLPTR;
|
||||
MenuActions *m_menuActions = Q_NULLPTR;
|
||||
|
||||
signals:
|
||||
void shutdownSignal(QUrl);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
<string>pgAdmin 4</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>pgAdmin 4</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.21.0</string>
|
||||
<string>4.26.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.21.0</string>
|
||||
<string>4.26.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.10</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
@@ -9,58 +9,74 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "LogWindow.h"
|
||||
#include "ui_LogWindow.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QTime>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
LogWindow::LogWindow(QWidget *parent, QString logFile) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::LogWindow),
|
||||
m_logFile(logFile)
|
||||
LogWindow::LogWindow(QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
initLogWindow();
|
||||
}
|
||||
|
||||
void LogWindow::initLogWindow()
|
||||
{
|
||||
ui = new Ui::LogWindow;
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
|
||||
LogWindow::~LogWindow()
|
||||
void LogWindow::LoadLog()
|
||||
{
|
||||
delete ui;
|
||||
int startupLines;
|
||||
int serverLines;
|
||||
|
||||
ui->lblStatus->setText(tr("Loading logfiles..."));
|
||||
|
||||
ui->lblStartupLog->setText(tr("Startup Log (%1):").arg(g_startupLogFile));
|
||||
ui->lblServerLog->setText(tr("Server Log (%1):").arg(g_serverLogFile));
|
||||
|
||||
startupLines = this->readLog(g_startupLogFile, ui->textStartupLog);
|
||||
serverLines = this->readLog(g_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;
|
||||
long len = 0;
|
||||
int i, lines = 0;
|
||||
int i;
|
||||
int lines = 0;
|
||||
|
||||
// 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(g_serverLogFile));
|
||||
this->setDisabled(false);
|
||||
QApplication::restoreOverrideCursor();
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the file size, and read the data
|
||||
@@ -70,20 +86,18 @@ void LogWindow::ReadLog()
|
||||
buffer = static_cast<char *>(malloc((len + 1) * sizeof(char)));
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (fread(buffer + i, 1, 1, log) > 0)
|
||||
{
|
||||
if (buffer[i] == '\n')
|
||||
lines++;
|
||||
}
|
||||
if (fread(buffer + i, 1, 1, log) > 0 && buffer[i] == '\n')
|
||||
lines++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#define LOGWINDOW_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
namespace Ui {
|
||||
class LogWindow;
|
||||
@@ -23,10 +24,8 @@ class LogWindow : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LogWindow(QWidget *parent = Q_NULLPTR, QString logFile = "");
|
||||
~LogWindow();
|
||||
|
||||
void ReadLog();
|
||||
explicit LogWindow(QWidget *parent = Q_NULLPTR);
|
||||
void LoadLog();
|
||||
|
||||
private slots:
|
||||
void reload();
|
||||
@@ -34,7 +33,8 @@ private slots:
|
||||
private:
|
||||
Ui::LogWindow *ui;
|
||||
|
||||
QString m_logFile;
|
||||
void initLogWindow();
|
||||
int readLog(QString logFile, QPlainTextEdit *logWidget);
|
||||
};
|
||||
|
||||
#endif // LOGWINDOW_H
|
||||
@@ -11,11 +11,43 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
<string>pgAdmin 4 Log</string>
|
||||
</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>
|
||||
|
||||
@@ -11,13 +11,18 @@
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QTextStream>
|
||||
#include <QStandardPaths>
|
||||
|
||||
Logger* Logger::m_pThis = Q_NULLPTR;
|
||||
QString Logger::m_sFileName = "";
|
||||
QFile* Logger::m_Logfile = Q_NULLPTR;
|
||||
|
||||
Logger::Logger()
|
||||
{
|
||||
}
|
||||
|
||||
Logger::~Logger()
|
||||
{
|
||||
}
|
||||
@@ -27,9 +32,8 @@ Logger* Logger::GetLogger()
|
||||
if (m_pThis == Q_NULLPTR)
|
||||
{
|
||||
m_pThis = new Logger();
|
||||
m_sFileName = QDir::homePath() + (QString("/.%1.startup.log").arg(PGA_APP_NAME)).remove(" ");
|
||||
m_Logfile = new QFile;
|
||||
m_Logfile->setFileName(m_sFileName);
|
||||
m_Logfile->setFileName(g_startupLogFile);
|
||||
m_Logfile->open(QIODevice::WriteOnly | QIODevice::Text);
|
||||
m_Logfile->setPermissions(QFile::ReadOwner|QFile::WriteOwner);
|
||||
}
|
||||
@@ -37,9 +41,9 @@ Logger* Logger::GetLogger()
|
||||
return m_pThis;
|
||||
}
|
||||
|
||||
void Logger::Log(const QString& sMessage)
|
||||
void Logger::Log(const QString& sMessage) const
|
||||
{
|
||||
QString text = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss ") + sMessage + "\n";
|
||||
QString text = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss: ") + sMessage + "\n";
|
||||
if (m_Logfile != Q_NULLPTR)
|
||||
{
|
||||
QTextStream out(m_Logfile);
|
||||
|
||||
@@ -20,15 +20,13 @@ class Logger : public QObject
|
||||
public:
|
||||
static Logger* GetLogger();
|
||||
static void ReleaseLogger();
|
||||
void Log(const QString& sMessage);
|
||||
void Log(const QString& sMessage) const;
|
||||
|
||||
private:
|
||||
Logger();
|
||||
virtual ~Logger();
|
||||
|
||||
private:
|
||||
static Logger* m_pThis;
|
||||
static QString m_sFileName;
|
||||
static QFile *m_Logfile;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,20 +9,18 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "MenuActions.h"
|
||||
|
||||
// QT headers
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QDesktopServices>
|
||||
#include <QEventLoop>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
|
||||
MenuActions::MenuActions()
|
||||
{
|
||||
m_logWindow = Q_NULLPTR;
|
||||
m_logFile = "";
|
||||
m_appServerUrl = "";
|
||||
}
|
||||
|
||||
MenuActions::~MenuActions()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,13 +29,9 @@ void MenuActions::setAppServerUrl(QString appServerUrl)
|
||||
m_appServerUrl = appServerUrl;
|
||||
}
|
||||
|
||||
void MenuActions::setLogFile(QString logFile)
|
||||
{
|
||||
m_logFile = logFile;
|
||||
}
|
||||
|
||||
// Create a new application browser window on user request
|
||||
void MenuActions::onNew()
|
||||
void MenuActions::onNew() const
|
||||
{
|
||||
QSettings settings;
|
||||
QString cmd = settings.value("BrowserCommand").toString();
|
||||
@@ -61,7 +55,7 @@ void MenuActions::onNew()
|
||||
|
||||
|
||||
// Copy the application server URL to the clipboard
|
||||
void MenuActions::onCopyUrl()
|
||||
void MenuActions::onCopyUrl() const
|
||||
{
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(m_appServerUrl);
|
||||
@@ -71,48 +65,25 @@ void MenuActions::onCopyUrl()
|
||||
// Show the config dialogue
|
||||
void MenuActions::onConfig()
|
||||
{
|
||||
QSettings settings;
|
||||
bool ok;
|
||||
if (!m_configWindow)
|
||||
m_configWindow = new ConfigWindow();
|
||||
|
||||
ConfigWindow *dlg = new ConfigWindow();
|
||||
dlg->setWindowTitle(QString(tr("%1 Configuration")).arg(PGA_APP_NAME));
|
||||
dlg->setBrowserCommand(settings.value("BrowserCommand").toString());
|
||||
dlg->setFixedPort(settings.value("FixedPort").toBool());
|
||||
dlg->setPortNumber(settings.value("PortNumber").toInt());
|
||||
dlg->setOpenTabAtStartup(settings.value("OpenTabAtStartup", true).toBool());
|
||||
dlg->setPythonPath(settings.value("PythonPath").toString());
|
||||
dlg->setApplicationPath(settings.value("ApplicationPath").toString());
|
||||
dlg->setModal(true);
|
||||
ok = dlg->exec();
|
||||
m_configWindow->setConfigValues();
|
||||
m_configWindow->show();
|
||||
m_configWindow->raise();
|
||||
m_configWindow->activateWindow();
|
||||
connect(m_configWindow, SIGNAL(accepted(bool)), this, SLOT(onConfigDone(bool)));
|
||||
}
|
||||
|
||||
QString browsercommand = dlg->getBrowserCommand();
|
||||
bool fixedport = dlg->getFixedPort();
|
||||
int portnumber = dlg->getPortNumber();
|
||||
bool opentabatstartup = dlg->getOpenTabAtStartup();
|
||||
QString pythonpath = dlg->getPythonPath();
|
||||
QString applicationpath = dlg->getApplicationPath();
|
||||
|
||||
if (ok)
|
||||
void MenuActions::onConfigDone(bool needRestart) const
|
||||
{
|
||||
if (needRestart && QMessageBox::Yes == QMessageBox::question(Q_NULLPTR,
|
||||
tr("Shut down server?"),
|
||||
tr("The pgAdmin 4 server must be restarted for changes to take effect. Do you want to shut down the server now?"),
|
||||
QMessageBox::Yes | QMessageBox::No))
|
||||
{
|
||||
bool needRestart = (settings.value("FixedPort").toBool() != fixedport ||
|
||||
settings.value("PortNumber").toInt() != portnumber ||
|
||||
settings.value("PythonPath").toString() != pythonpath ||
|
||||
settings.value("ApplicationPath").toString() != applicationpath);
|
||||
|
||||
settings.setValue("BrowserCommand", browsercommand);
|
||||
settings.setValue("FixedPort", fixedport);
|
||||
settings.setValue("PortNumber", portnumber);
|
||||
settings.setValue("OpenTabAtStartup", opentabatstartup);
|
||||
settings.setValue("PythonPath", pythonpath);
|
||||
settings.setValue("ApplicationPath", applicationpath);
|
||||
|
||||
if (needRestart)
|
||||
{
|
||||
if (QMessageBox::Yes == QMessageBox::question(Q_NULLPTR, tr("Shut down server?"), QString(tr("The %1 server must be restarted for changes to take effect. Do you want to shut down the server now?")).arg(PGA_APP_NAME), QMessageBox::Yes | QMessageBox::No))
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,28 +94,25 @@ void MenuActions::onLog()
|
||||
QSettings settings;
|
||||
|
||||
if (!m_logWindow)
|
||||
{
|
||||
m_logWindow = new LogWindow(Q_NULLPTR, m_logFile);
|
||||
m_logWindow->setWindowTitle(QString(tr("%1 Log")).arg(PGA_APP_NAME));
|
||||
}
|
||||
m_logWindow = new LogWindow();
|
||||
|
||||
m_logWindow->show();
|
||||
m_logWindow->raise();
|
||||
m_logWindow->activateWindow();
|
||||
|
||||
QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
|
||||
|
||||
m_logWindow->ReadLog();
|
||||
m_logWindow->LoadLog();
|
||||
}
|
||||
|
||||
|
||||
// Exit
|
||||
void MenuActions::onQuit()
|
||||
{
|
||||
if (QMessageBox::Yes == QMessageBox::question(Q_NULLPTR, tr("Shut down server?"), QString(tr("Are you sure you want to shut down the %1 server?")).arg(PGA_APP_NAME), QMessageBox::Yes | QMessageBox::No))
|
||||
if (QMessageBox::Yes == QMessageBox::question(Q_NULLPTR, tr("Shut down server?"), tr("Are you sure you want to shut down the pgAdmin 4 server?"), QMessageBox::Yes | QMessageBox::No))
|
||||
{
|
||||
// Emit the signal to shut down the python server.
|
||||
emit shutdownSignal(m_appServerUrl);
|
||||
exit(0);
|
||||
QApplication::quit();
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,6 @@
|
||||
#ifndef MENUACTIONS_H
|
||||
#define MENUACTIONS_H
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
|
||||
// App headers
|
||||
#include "LogWindow.h"
|
||||
#include "ConfigWindow.h"
|
||||
|
||||
@@ -23,19 +20,21 @@ class MenuActions: public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
MenuActions();
|
||||
~MenuActions();
|
||||
|
||||
void setAppServerUrl(QString appServerUrl);
|
||||
void setLogFile(QString logFile);
|
||||
QString getAppServerUrl() { return m_appServerUrl; }
|
||||
QString getAppServerUrl() const { return m_appServerUrl; }
|
||||
|
||||
private:
|
||||
QString m_appServerUrl, m_logFile;
|
||||
LogWindow *m_logWindow;
|
||||
QString m_appServerUrl = "";
|
||||
LogWindow *m_logWindow = Q_NULLPTR;
|
||||
ConfigWindow *m_configWindow = Q_NULLPTR;
|
||||
|
||||
public slots:
|
||||
void onConfigDone(bool needRestart) const;
|
||||
|
||||
protected slots:
|
||||
void onNew();
|
||||
void onCopyUrl();
|
||||
void onNew() const;
|
||||
void onCopyUrl() const;
|
||||
void onConfig();
|
||||
void onLog();
|
||||
void onQuit();
|
||||
|
||||
@@ -0,0 +1,660 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
// Runtime.cpp - Core of the runtime
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "Runtime.h"
|
||||
#include "Server.h"
|
||||
#include "TrayIcon.h"
|
||||
#include "MenuActions.h"
|
||||
#include "ConfigWindow.h"
|
||||
#include "FloatingWindow.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "macos.h"
|
||||
#endif
|
||||
|
||||
// Must be before QT
|
||||
#include <Python.h>
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QTime>
|
||||
|
||||
|
||||
Runtime::Runtime()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool Runtime::go(int argc, char *argv[])
|
||||
{
|
||||
// Before starting main application, need to set 'QT_X11_NO_MITSHM=1'
|
||||
// to make the runtime work with IBM PPC machines.
|
||||
#if defined (Q_OS_LINUX)
|
||||
QByteArray val("1");
|
||||
qputenv("QT_X11_NO_MITSHM", val);
|
||||
#endif
|
||||
|
||||
// Create the QT application
|
||||
QApplication app(argc, argv);
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
|
||||
// Setup look n feel
|
||||
setupStyling(&app);
|
||||
|
||||
// Setup the settings management
|
||||
QCoreApplication::setOrganizationName("pgadmin");
|
||||
QCoreApplication::setOrganizationDomain("pgadmin.org");
|
||||
QCoreApplication::setApplicationName("pgadmin4");
|
||||
|
||||
QSettings settings;
|
||||
|
||||
// Interlock
|
||||
if (alreadyRunning())
|
||||
exit(0);
|
||||
|
||||
// Proxy config
|
||||
configureProxy();
|
||||
|
||||
// Display the spash screen
|
||||
m_splash = displaySplash(&app);
|
||||
|
||||
// Generate a random key to authenticate the client to the server
|
||||
QString key = QUuid::createUuid().toString();
|
||||
key = key.mid(1, key.length() - 2);
|
||||
|
||||
// Create Menu Actions
|
||||
MenuActions *menuActions = new MenuActions();
|
||||
|
||||
// Create the control object (tray icon or floating window
|
||||
m_splash->showMessage(QString(QWidget::tr("Checking for system tray...")), Qt::AlignBottom | Qt::AlignCenter);
|
||||
|
||||
if (QSystemTrayIcon::isSystemTrayAvailable())
|
||||
m_trayIcon = createTrayIcon(menuActions);
|
||||
else
|
||||
m_floatingWindow = createFloatingWindow(menuActions);
|
||||
|
||||
// Fire up the app server
|
||||
const Server *server = startServerLoop(key);
|
||||
|
||||
// Ensure we'll cleanup
|
||||
QObject::connect(server, SIGNAL(finished()), server, SLOT(deleteLater()));
|
||||
atexit(cleanup);
|
||||
|
||||
// Generate the app server URL
|
||||
QString url = QString("http://127.0.0.1:%1/?key=%2").arg(m_port).arg(key);
|
||||
Logger::GetLogger()->Log(QString(QWidget::tr("Application Server URL: %1")).arg(url));
|
||||
|
||||
// Check the server is running
|
||||
checkServer(url);
|
||||
|
||||
// Stash the URL for any duplicate processes to open
|
||||
createAddressFile(url);
|
||||
|
||||
// Go!
|
||||
menuActions->setAppServerUrl(url);
|
||||
|
||||
// Enable the shutdown server menu as server started successfully.
|
||||
if (m_trayIcon != Q_NULLPTR)
|
||||
m_trayIcon->enablePostStartOptions();
|
||||
if (m_floatingWindow != Q_NULLPTR)
|
||||
m_floatingWindow->enablePostStartOptions();
|
||||
|
||||
// Open the browser if needed
|
||||
if (settings.value("OpenTabAtStartup", true).toBool())
|
||||
openBrowserTab(url);
|
||||
|
||||
// Make sure the server is shutdown if the server is quit by the user
|
||||
QObject::connect(menuActions, SIGNAL(shutdownSignal(QUrl)), server, SLOT(shutdown(QUrl)));
|
||||
|
||||
// Final cleanup
|
||||
m_splash->finish(Q_NULLPTR);
|
||||
|
||||
if (m_floatingWindow != Q_NULLPTR)
|
||||
m_floatingWindow->show();
|
||||
|
||||
Logger::GetLogger()->Log("Everything works fine, successfully started pgAdmin4.");
|
||||
Logger::ReleaseLogger();
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
||||
// Setup the styling
|
||||
void Runtime::setupStyling(QApplication *app) const
|
||||
{
|
||||
// Setup the styling
|
||||
#ifndef Q_OS_LINUX
|
||||
QFile stylesheet;
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
QSettings registry("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::Registry64Format);
|
||||
if (!registry.value("AppsUseLightTheme", true).toBool())
|
||||
{
|
||||
qDebug( "Windows Dark Mode..." );
|
||||
stylesheet.setFileName(":/qdarkstyle/style.qss");
|
||||
stylesheet.open(QFile::ReadOnly | QFile::Text);
|
||||
QTextStream stream(&stylesheet);
|
||||
app->setStyleSheet(stream.readAll());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
if (IsDarkMode())
|
||||
{
|
||||
qDebug( "macOS Dark Mode...");
|
||||
stylesheet.setFileName(":/qdarkstyle/style.qss");
|
||||
stylesheet.open(QFile::ReadOnly | QFile::Text);
|
||||
QTextStream stream(&stylesheet);
|
||||
app->setStyleSheet(stream.readAll());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set high DPI pixmap to display icons clear on Qt widget.
|
||||
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
}
|
||||
|
||||
// Check if we're already running. If we are, open a new browser tab.
|
||||
bool Runtime::alreadyRunning()
|
||||
{
|
||||
// Create a system-wide semaphore keyed by app name, exe hash and the username
|
||||
// to ensure instances are unique to the user and path
|
||||
QString userName = qgetenv("USER"); // *nix
|
||||
if (userName.isEmpty())
|
||||
userName = qgetenv("USERNAME"); // Windows
|
||||
|
||||
QString semaName = QString("pgadmin4-%1-%2-sema").arg(userName).arg(getExeHash());
|
||||
QString shmemName = QString("pgadmin4-%1-%2-shmem").arg(userName).arg(getExeHash());
|
||||
qDebug() << "Semaphore name:" << semaName;
|
||||
qDebug() << "Shared memory segment name:" << shmemName;
|
||||
|
||||
QSystemSemaphore sema(semaName, 1);
|
||||
sema.acquire();
|
||||
|
||||
#ifndef Q_OS_WIN32
|
||||
// We may need to clean up stale shmem segments on *nix. Attaching and detaching
|
||||
// should remove the segment if it is orphaned.
|
||||
QSharedMemory stale_shmem(shmemName);
|
||||
if (stale_shmem.attach())
|
||||
stale_shmem.detach();
|
||||
#endif
|
||||
|
||||
m_shmem = new QSharedMemory(shmemName);
|
||||
bool is_running;
|
||||
if (m_shmem->attach())
|
||||
is_running = true;
|
||||
else
|
||||
{
|
||||
m_shmem->create(1);
|
||||
is_running = false;
|
||||
}
|
||||
sema.release();
|
||||
|
||||
if (is_running)
|
||||
{
|
||||
QFile addressFile(g_addressFile);
|
||||
addressFile.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
QTextStream in(&addressFile);
|
||||
QString url = in.readLine();
|
||||
|
||||
qDebug() << "Already running. Opening browser tab to: " << url << "and exiting.";
|
||||
openBrowserTab(url);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Runtime::configureProxy() const
|
||||
{
|
||||
// In windows and linux, it is required to set application level proxy
|
||||
// because socket bind logic to find free port gives socket creation error
|
||||
// when system proxy is configured. We are also setting
|
||||
// "setUseSystemConfiguration"=true to use the system proxy which will
|
||||
// override this application level proxy. As this bug is fixed in Qt 5.9 so
|
||||
// need to set application proxy for Qt version < 5.9.
|
||||
//
|
||||
#if defined (Q_OS_WIN) && QT_VERSION <= 0x050800
|
||||
// Give dummy URL required to find proxy server configured in windows.
|
||||
QNetworkProxyQuery proxyQuery(QUrl("https://www.pgadmin.org"));
|
||||
QNetworkProxy l_proxy;
|
||||
QList<QNetworkProxy> listOfProxies = QNetworkProxyFactory::systemProxyForQuery(proxyQuery);
|
||||
|
||||
if (listOfProxies.size())
|
||||
{
|
||||
l_proxy = listOfProxies[0];
|
||||
|
||||
// If host name is not empty means proxy server is configured.
|
||||
if (!l_proxy.hostName().isEmpty()) {
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (Q_OS_LINUX) && QT_VERSION <= 0x050800
|
||||
QByteArray proxy_env;
|
||||
proxy_env = qgetenv("http_proxy");
|
||||
// If http_proxy environment is defined in linux then proxy server is configured.
|
||||
if (!proxy_env.isEmpty()) {
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Display the splash screen
|
||||
QSplashScreen * Runtime::displaySplash(QApplication *app)
|
||||
{
|
||||
QSplashScreen *splash = new QSplashScreen();
|
||||
splash->setPixmap(QPixmap(":/splash.png"));
|
||||
splash->setWindowFlags(splash->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
splash->show();
|
||||
app->processEvents(QEventLoop::AllEvents);
|
||||
|
||||
return splash;
|
||||
}
|
||||
|
||||
|
||||
// Get the port number we're going to use
|
||||
quint16 Runtime::getPort() const
|
||||
{
|
||||
quint16 port = 0L;
|
||||
QSettings settings;
|
||||
|
||||
if (settings.value("FixedPort", false).toBool())
|
||||
{
|
||||
// Use the fixed port number
|
||||
port = settings.value("PortNumber", 5050).toUInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find an unused port number. Essentially, we're just reserving one
|
||||
// here that Flask will use when we start up the server.
|
||||
QTcpSocket socket;
|
||||
|
||||
#if QT_VERSION >= 0x050900
|
||||
socket.setProxy(QNetworkProxy::NoProxy);
|
||||
#endif
|
||||
|
||||
socket.bind(0, QTcpSocket::ShareAddress);
|
||||
port = socket.localPort();
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
// Create a tray icon
|
||||
TrayIcon * Runtime::createTrayIcon(MenuActions *menuActions)
|
||||
{
|
||||
TrayIcon *trayIcon = Q_NULLPTR;
|
||||
|
||||
m_splash->showMessage(QString(QWidget::tr("Checking for system tray...")), Qt::AlignBottom | Qt::AlignCenter);
|
||||
Logger::GetLogger()->Log("Checking for system tray...");
|
||||
|
||||
// Start the tray service
|
||||
trayIcon = new TrayIcon();
|
||||
|
||||
// Set the MenuActions object to connect to slot
|
||||
if (trayIcon != Q_NULLPTR)
|
||||
trayIcon->setMenuActions(menuActions);
|
||||
|
||||
trayIcon->Init();
|
||||
|
||||
return trayIcon;
|
||||
}
|
||||
|
||||
|
||||
// Create a floating window
|
||||
FloatingWindow * Runtime::createFloatingWindow(MenuActions *menuActions)
|
||||
{
|
||||
FloatingWindow *floatingWindow = Q_NULLPTR;
|
||||
|
||||
m_splash->showMessage(QString(QWidget::tr("System tray not found, creating floating window...")), Qt::AlignBottom | Qt::AlignCenter);
|
||||
Logger::GetLogger()->Log("System tray not found, creating floating window...");
|
||||
floatingWindow = new FloatingWindow();
|
||||
if (floatingWindow == Q_NULLPTR)
|
||||
{
|
||||
QString error = QString(QWidget::tr("Unable to initialize either a tray icon or floating window."));
|
||||
QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
|
||||
Logger::GetLogger()->Log(error);
|
||||
Logger::ReleaseLogger();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Set the MenuActions object to connect to slot
|
||||
floatingWindow->setMenuActions(menuActions);
|
||||
floatingWindow->Init();
|
||||
|
||||
return floatingWindow;
|
||||
}
|
||||
|
||||
|
||||
void Runtime::openConfigureWindow(const QString errorMsg)
|
||||
{
|
||||
m_splash->finish(Q_NULLPTR);
|
||||
|
||||
qDebug() << errorMsg;
|
||||
QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), errorMsg);
|
||||
Logger::GetLogger()->Log(errorMsg);
|
||||
|
||||
// Allow the user to tweak the configuration if needed
|
||||
m_configDone = false;
|
||||
QSettings settings;
|
||||
bool oldFixedPort = settings.value("FixedPort", false).toBool();
|
||||
|
||||
|
||||
ConfigWindow *dlg = new ConfigWindow();
|
||||
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dlg->show();
|
||||
dlg->raise();
|
||||
dlg->activateWindow();
|
||||
QObject::connect(dlg, SIGNAL(closing(bool)), this, SLOT(onConfigDone(bool)));
|
||||
|
||||
// Wait for configuration to be completed
|
||||
while (!m_configDone)
|
||||
delay(100);
|
||||
|
||||
// Read the value of port again if user has changed.
|
||||
bool newFixedPort = settings.value("FixedPort", false).toBool();
|
||||
quint16 newPort = settings.value("PortNumber").toUInt();
|
||||
|
||||
// User hasn't changed the value of fixed port check box
|
||||
// only change the value of the port
|
||||
if (oldFixedPort == newFixedPort && newFixedPort && m_port != newPort)
|
||||
m_port = newPort;
|
||||
// User has selected the fixed port and it's old value is random port,
|
||||
// so port needs to be updated.
|
||||
else if (oldFixedPort != newFixedPort && newFixedPort)
|
||||
m_port = newPort;
|
||||
// User has deselect the fixed port and it's old value is fixed port,
|
||||
// so we will have to get the random port
|
||||
else if (oldFixedPort != newFixedPort && !newFixedPort)
|
||||
m_port = getPort();
|
||||
}
|
||||
|
||||
// Server startup loop
|
||||
Server * Runtime::startServerLoop(QString key)
|
||||
{
|
||||
bool done = false;
|
||||
Server *server;
|
||||
|
||||
// Get the port number to use
|
||||
m_port = getPort();
|
||||
|
||||
while (!done)
|
||||
{
|
||||
server = startServer(key);
|
||||
if (server == NULL)
|
||||
{
|
||||
Logger::ReleaseLogger();
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
// Check for server startup errors
|
||||
if (server->isFinished() || server->getError().length() > 0)
|
||||
{
|
||||
QString error = QString(QWidget::tr("An error occurred initialising the pgAdmin 4 server:\n\n%1")).arg(server->getError());
|
||||
|
||||
delete server;
|
||||
|
||||
// Enable the View Log option for diagnostics
|
||||
if (m_floatingWindow)
|
||||
m_floatingWindow->enableViewLogOption();
|
||||
if (m_trayIcon)
|
||||
m_trayIcon->enableViewLogOption();
|
||||
|
||||
// Open the configuration window
|
||||
openConfigureWindow(error);
|
||||
|
||||
// Disable the View Log option again
|
||||
if (m_floatingWindow)
|
||||
m_floatingWindow->disableViewLogOption();
|
||||
if (m_trayIcon)
|
||||
m_trayIcon->disableViewLogOption();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Startup appears successful
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
// Slot called when re-configuration is done.
|
||||
void Runtime::onConfigDone(bool accepted)
|
||||
{
|
||||
if (accepted)
|
||||
m_configDone = true;
|
||||
else
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
// Start the server
|
||||
Server * Runtime::startServer(QString key)
|
||||
{
|
||||
Server *server;
|
||||
|
||||
m_splash->showMessage(QString(QWidget::tr("Starting pgAdmin4 server...")), Qt::AlignBottom | Qt::AlignCenter);
|
||||
Logger::GetLogger()->Log("Starting pgAdmin4 server...");
|
||||
|
||||
QString msg = QString(QWidget::tr("Creating server object, port:%1, key:%2, logfile:%3")).arg(m_port).arg(key).arg(g_serverLogFile);
|
||||
Logger::GetLogger()->Log(msg);
|
||||
server = new Server(this, m_port, key, g_serverLogFile);
|
||||
|
||||
Logger::GetLogger()->Log("Initializing server...");
|
||||
if (!server->Init())
|
||||
{
|
||||
m_splash->finish(Q_NULLPTR);
|
||||
|
||||
qDebug() << server->getError();
|
||||
|
||||
QString error = QString(QWidget::tr("An error occurred initialising the pgAdmin 4 server:\n\n%1")).arg(server->getError());
|
||||
QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
|
||||
|
||||
Logger::GetLogger()->Log(error);
|
||||
Logger::ReleaseLogger();
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger::GetLogger()->Log("Server initialized, starting server thread...");
|
||||
server->start();
|
||||
|
||||
// This is a hack to give the server a chance to start and potentially fail. As
|
||||
// the Python interpreter is a synchronous call, we can't check for proper startup
|
||||
// easily in a more robust way - we have to rely on a clean startup not returning.
|
||||
// It should always fail pretty quickly, and take longer to start if it succeeds, so
|
||||
// we don't really get a visible delay here.
|
||||
delay(1000);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
// Check the server is running properly
|
||||
void Runtime::checkServer(QString url)
|
||||
{
|
||||
// Read the server connection timeout from the registry or set the default timeout.
|
||||
QSettings settings;
|
||||
int timeout = settings.value("ConnectionTimeout", 90).toInt();
|
||||
|
||||
// Now the server should be up, we'll attempt to connect and get a response.
|
||||
// We'll retry in a loop a few time before aborting if necessary.
|
||||
|
||||
QTime endTime = QTime::currentTime().addSecs(timeout);
|
||||
QTime midTime1 = QTime::currentTime().addSecs(timeout/3);
|
||||
QTime midTime2 = QTime::currentTime().addSecs(timeout*2/3);
|
||||
bool alive = false;
|
||||
bool enableOptions = false;
|
||||
|
||||
Logger::GetLogger()->Log("The server should be up. Attempting to connect and get a response.");
|
||||
while(QTime::currentTime() <= endTime)
|
||||
{
|
||||
alive = pingServer(QUrl(url));
|
||||
|
||||
if (alive)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(QTime::currentTime() >= midTime1)
|
||||
{
|
||||
if (m_floatingWindow && !enableOptions)
|
||||
{
|
||||
m_floatingWindow->enableViewLogOption();
|
||||
m_floatingWindow->enableConfigOption();
|
||||
enableOptions = true;
|
||||
}
|
||||
|
||||
if (m_trayIcon && !enableOptions)
|
||||
{
|
||||
m_trayIcon->enableViewLogOption();
|
||||
m_trayIcon->enableConfigOption();
|
||||
enableOptions = true;
|
||||
}
|
||||
|
||||
if(QTime::currentTime() < midTime2) {
|
||||
m_splash->showMessage(QString(QWidget::tr("Taking longer than usual...")), Qt::AlignBottom | Qt::AlignCenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_splash->showMessage(QString(QWidget::tr("Almost there...")), Qt::AlignBottom | Qt::AlignCenter);
|
||||
}
|
||||
}
|
||||
|
||||
delay(200);
|
||||
}
|
||||
|
||||
// Attempt to connect one more time in case of a long network timeout while looping
|
||||
Logger::GetLogger()->Log("Attempt to connect one more time in case of a long network timeout while looping");
|
||||
if (!alive && !pingServer(QUrl(url)))
|
||||
{
|
||||
m_splash->finish(Q_NULLPTR);
|
||||
QString error(QWidget::tr("The pgAdmin 4 server could not be contacted."));
|
||||
QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
|
||||
|
||||
Logger::ReleaseLogger();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create the address file
|
||||
void Runtime::createAddressFile(QString url) const
|
||||
{
|
||||
QFile addressFile(g_addressFile);
|
||||
if (addressFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
addressFile.setPermissions(QFile::ReadOwner|QFile::WriteOwner);
|
||||
QTextStream out(&addressFile);
|
||||
out << url << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Open a browser tab
|
||||
void Runtime::openBrowserTab(QString url) const
|
||||
{
|
||||
QSettings settings;
|
||||
QString cmd = settings.value("BrowserCommand").toString();
|
||||
|
||||
if (!cmd.isEmpty())
|
||||
{
|
||||
cmd.replace("%URL%", url);
|
||||
QProcess::startDetached(cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QDesktopServices::openUrl(url))
|
||||
{
|
||||
QString error(QWidget::tr("Failed to open the system default web browser. Is one installed?."));
|
||||
QMessageBox::critical(Q_NULLPTR, QString(QWidget::tr("Fatal Error")), error);
|
||||
|
||||
Logger::GetLogger()->Log(error);
|
||||
Logger::ReleaseLogger();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Make a request to the Python API server
|
||||
QString Runtime::serverRequest(QUrl url, QString path)
|
||||
{
|
||||
QNetworkAccessManager manager;
|
||||
QEventLoop loop;
|
||||
QNetworkReply *reply;
|
||||
QVariant redirectUrl;
|
||||
|
||||
|
||||
url.setPath(path);
|
||||
QString requestUrl = url.toString();
|
||||
|
||||
do
|
||||
{
|
||||
reply = manager.get(QNetworkRequest(url));
|
||||
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
loop.exec();
|
||||
|
||||
redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
url = redirectUrl.toUrl();
|
||||
|
||||
if (!redirectUrl.isNull())
|
||||
delete reply;
|
||||
|
||||
} while (!redirectUrl.isNull());
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
qDebug() << "Failed to connect to the server:" << reply->errorString() << "- request URL:" << requestUrl << ".";
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString response = reply->readAll();
|
||||
qDebug() << "Server response:" << response << "- request URL:" << requestUrl << ".";
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
// Ping the application server to see if it's alive
|
||||
bool Runtime::pingServer(QUrl url)
|
||||
{
|
||||
return serverRequest(url, "/misc/ping") == "PING";
|
||||
}
|
||||
|
||||
|
||||
// Shutdown the application server
|
||||
bool Runtime::shutdownServer(QUrl url)
|
||||
{
|
||||
return serverRequest(url, "/misc/shutdown") == "SHUTDOWN";
|
||||
}
|
||||
|
||||
|
||||
void Runtime::delay(int milliseconds) const
|
||||
{
|
||||
QTime endTime = QTime::currentTime().addMSecs(milliseconds);
|
||||
while(QTime::currentTime() < endTime)
|
||||
{
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
// Runtime.h - Core of the runtime
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef RUNTIME_H
|
||||
#define RUNTIME_H
|
||||
|
||||
// Include the Python header here as it needs to appear before any QT
|
||||
// headers anywhere in the app.
|
||||
#ifdef __MINGW32__
|
||||
#include <cmath>
|
||||
#endif
|
||||
#include <Python.h>
|
||||
|
||||
#include "TrayIcon.h"
|
||||
#include "MenuActions.h"
|
||||
#include "FloatingWindow.h"
|
||||
|
||||
// QT headers
|
||||
#include <QtWidgets>
|
||||
|
||||
class Server;
|
||||
|
||||
class Runtime: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Runtime();
|
||||
|
||||
bool alreadyRunning();
|
||||
bool go(int argc, char *argv[]);
|
||||
void delay(int milliseconds) const;
|
||||
bool shutdownServer(QUrl url);
|
||||
|
||||
private:
|
||||
QSharedMemory *m_shmem;
|
||||
bool m_configDone;
|
||||
FloatingWindow *m_floatingWindow = Q_NULLPTR;
|
||||
TrayIcon *m_trayIcon = Q_NULLPTR;
|
||||
QSplashScreen *m_splash = Q_NULLPTR;
|
||||
quint16 m_port = 0;
|
||||
|
||||
void setupStyling(QApplication *app) const;
|
||||
void configureProxy() const;
|
||||
QSplashScreen *displaySplash(QApplication *app);
|
||||
quint16 getPort() const;
|
||||
TrayIcon *createTrayIcon(MenuActions *menuActions);
|
||||
FloatingWindow *createFloatingWindow(MenuActions *menuActions);
|
||||
Server *startServerLoop(QString key);
|
||||
Server *startServer(QString key);
|
||||
void checkServer(QString url);
|
||||
void createAddressFile(QString url) const;
|
||||
void openBrowserTab(QString url) const;
|
||||
QString serverRequest(QUrl url, QString path);
|
||||
bool pingServer(QUrl url);
|
||||
void openConfigureWindow(const QString errorMsg);
|
||||
|
||||
private slots:
|
||||
void onConfigDone(bool accepted);
|
||||
};
|
||||
|
||||
#endif // RUNTIME_H
|
||||
@@ -10,19 +10,21 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pgAdmin4.h"
|
||||
#include "Logger.h"
|
||||
|
||||
// Must be before QT
|
||||
#include <Python.h>
|
||||
|
||||
#include "Server.h"
|
||||
#include "Logger.h"
|
||||
|
||||
// QT headers
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
|
||||
// App headers
|
||||
#include "Server.h"
|
||||
|
||||
static void add_to_path(QString &python_path, QString path, bool prepend=false)
|
||||
{
|
||||
@@ -55,41 +57,32 @@ static void add_to_path(QString &python_path, QString path, bool prepend=false)
|
||||
}
|
||||
}
|
||||
|
||||
Server::Server(quint16 port, QString key, QString logFileName)
|
||||
Server::Server(Runtime *runtime, quint16 port, QString key, QString logFileName):
|
||||
m_runtime(runtime),
|
||||
m_port(port),
|
||||
m_key(key),
|
||||
m_logFileName(logFileName)
|
||||
{
|
||||
// Appserver port etc
|
||||
m_port = port;
|
||||
m_key = key;
|
||||
m_logFileName = logFileName;
|
||||
m_wcAppName = Q_NULLPTR;
|
||||
m_wcPythonHome = Q_NULLPTR;
|
||||
|
||||
// Initialise Python
|
||||
Py_NoSiteFlag=1;
|
||||
Py_NoUserSiteDirectory=1;
|
||||
Py_DontWriteBytecodeFlag=1;
|
||||
|
||||
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 char *appName = QString("pgAdmin 4").toUtf8();
|
||||
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;
|
||||
QString python_path = settings.value("PythonPath").toString();
|
||||
|
||||
// Get the application directory
|
||||
QString app_dir = qApp->applicationDirPath(),
|
||||
path_env = qgetenv("PATH"),
|
||||
pythonHome;
|
||||
QString app_dir = QCoreApplication::applicationDirPath();
|
||||
QString path_env = qgetenv("PATH");
|
||||
QString pythonHome;
|
||||
QStringList path_list;
|
||||
int i;
|
||||
|
||||
@@ -182,17 +175,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);
|
||||
const char *python_home = pythonHome.toUtf8().data();
|
||||
const size_t home_size = strlen(python_home) + 1;
|
||||
m_wcPythonHome = new wchar_t[home_size];
|
||||
mbstowcs (m_wcPythonHome, python_home, home_size);
|
||||
|
||||
Py_SetPythonHome(m_wcPythonHome);
|
||||
#endif
|
||||
}
|
||||
|
||||
Logger::GetLogger()->Log("Initializing Python...");
|
||||
@@ -207,15 +195,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 +207,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 +233,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,32 +323,14 @@ 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,
|
||||
* which might allow local users to execute arbitrary code via a Trojan horse Python file in the current working directory.
|
||||
* Here we have to set arguments explicitly to python interpreter. Check more details in 'PySys_SetArgv' documentation.
|
||||
*/
|
||||
char *appName = m_appfile_utf8.data();
|
||||
const char *appName = m_appfile_utf8.data();
|
||||
const size_t cSize = strlen(appName)+1;
|
||||
wchar_t* wcAppName = new wchar_t[cSize];
|
||||
mbstowcs (wcAppName, appName, cSize);
|
||||
@@ -385,19 +343,21 @@ 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);
|
||||
}
|
||||
|
||||
void Server::shutdown(QUrl url)
|
||||
{
|
||||
bool shotdown = shutdownServer(url);
|
||||
if (!shotdown)
|
||||
if (!m_runtime->shutdownServer(url))
|
||||
setError(tr("Failed to shut down application server thread."));
|
||||
|
||||
QThread::quit();
|
||||
QThread::wait();
|
||||
while(!this->isFinished()){}
|
||||
while(!this->isFinished())
|
||||
{
|
||||
Logger::GetLogger()->Log("Waiting for server to shut down.");
|
||||
m_runtime->delay(250);
|
||||
}
|
||||
}
|
||||
|
||||