1{
2 lib,
3 python3,
4 fetchFromGitHub,
5 zlib,
6 nixosTests,
7 postgresqlTestHook,
8 postgresql,
9 yarn-berry_4,
10 nodejs,
11 autoconf,
12 automake,
13 libtool,
14 libpng,
15 nasm,
16 cmake,
17 pkg-config,
18 stdenv,
19 srcOnly,
20 server-mode ? true,
21}:
22
23let
24 pname = "pgadmin";
25 version = "9.5";
26 yarnHash = "sha256-i3WCEpcZepB7K0A4QgjoLfkO7icew/8usJCo4DkWT6I=";
27
28 src = fetchFromGitHub {
29 owner = "pgadmin-org";
30 repo = "pgadmin4";
31 rev = "REL-${lib.versions.major version}_${lib.versions.minor version}";
32 hash = "sha256-5FwYkdhpg/2Cidi2qiFhhsQYbIwsp80K3MNxw5rp4ww=";
33 };
34
35 mozjpeg-bin = fetchFromGitHub {
36 owner = "imagemin";
37 repo = "mozjpeg-bin";
38 rev = "c0587fbc00b21ed8cad8bae499a0827baeaf7ffa";
39 hash = "sha256-D/pXQBlIIyk7KAgxJ1gKqxYxtlfBbLzUSmYZbH659cA=";
40 };
41
42 # keep the scope, as it is used throughout the derivation and tests
43 # this also makes potential future overrides easier
44 pythonPackages = python3.pkgs.overrideScope (final: prev: { });
45
46 # don't bother to test kerberos authentication
47 # skip tests on macOS which fail due to an error in keyring, see https://github.com/NixOS/nixpkgs/issues/281214
48 skippedTests = builtins.concatStringsSep "," (
49 [ "browser.tests.test_kerberos_with_mocking" ]
50 ++ lib.optionals stdenv.hostPlatform.isDarwin [
51 "browser.server_groups.servers.tests.test_all_server_get"
52 "browser.server_groups.servers.tests.test_check_connect"
53 "browser.server_groups.servers.tests.test_check_ssh_mock_connect"
54 "browser.server_groups.servers.tests.test_is_password_saved"
55 ]
56 );
57in
58
59pythonPackages.buildPythonApplication rec {
60 inherit pname version src;
61
62 offlineCache = yarn-berry_4.fetchYarnBerryDeps {
63 # mozjpeg fails to build on darwin due to a hardocded path
64 # this has been fixed upstream on master but no new version
65 # has been released. We therefore point yarn to upstream
66 # see https://github.com/imagemin/mozjpeg-bin/issues/64
67 # and https://github.com/imagemin/mozjpeg-bin/issues/81
68 patches = [
69 ./mozjpeg.patch
70 ];
71 src = src + "/web";
72 hash = yarnHash;
73 };
74
75 # from Dockerfile
76 CPPFLAGS = "-DPNG_ARM_NEON_OPT=0";
77
78 format = "setuptools";
79
80 patches = [
81 # Expose setup.py for later use
82 ./expose-setup.py.patch
83 # check for permission of /etc/pgadmin/config_system and don't fail
84 ./check-system-config-dir.patch
85 ];
86
87 postPatch = ''
88 # the patch needs to be executed inside the /web subfolder
89 # therefore it is included here and not in `patches`
90 cd web
91 patch -u yarn.lock ${./mozjpeg.patch}
92 cd ..
93 # patching Makefile, so it doesn't try to build sphinx documentation here
94 # (will do so later)
95 substituteInPlace Makefile \
96 --replace-fail 'LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 $(MAKE) -C docs/en_US -f Makefile.sphinx html' "true"
97
98 # fix document which refers a non-existing document and fails
99 substituteInPlace docs/en_US/contributions.rst \
100 --replace-fail "code_snippets" ""
101 # relax dependencies
102 sed 's|==|>=|g' -i requirements.txt
103 # fix extra_require error with "*" in match
104 sed 's|*|0|g' -i requirements.txt
105 substituteInPlace pkg/pip/setup_pip.py \
106 --replace-fail "req = req.replace('psycopg[c]', 'psycopg[binary]')" "req = req"
107 ${lib.optionalString (!server-mode) ''
108 substituteInPlace web/config.py \
109 --replace-fail "SERVER_MODE = True" "SERVER_MODE = False"
110 ''}
111 '';
112
113 dontYarnBerryInstallDeps = true;
114 env.YARN_ENABLE_SCRIPTS = "0";
115 dontUseCmakeConfigure = true;
116
117 preBuild = ''
118 # Adapted from pkg/pip/build.sh
119 echo Creating required directories...
120 mkdir -p pip-build/pgadmin4/docs
121
122 echo Building the documentation
123 cd docs/en_US
124 sphinx-build -W -b html -d _build/doctrees . _build/html
125
126 # Build the clean tree
127 cd ..
128 cp -r * ../pip-build/pgadmin4/docs
129 for DIR in `ls -d ??_??/`
130 do
131 if [ -d ''${DIR}_build/html ]; then
132 mkdir -p ../pip-build/pgadmin4/docs/''${DIR}_build
133 cp -R ''${DIR}_build/html ../pip-build/pgadmin4/docs/''${DIR}_build
134 fi
135 done
136 cd ../
137
138 echo Building the web frontend...
139 cd web
140 (
141 export LD=$CC # https://github.com/imagemin/optipng-bin/issues/108
142 yarnBerryConfigHook
143 )
144 # mozjpeg vendored source isn't included in the checkout for yarn. If we copy it before the
145 # yarnConfigHook it will just get overwritten. So we first run the configHook without build,
146 # then copy the vendored source and then build the dependencies
147 # This has the disadvantage of repeating some of the yarnConfigHooks logic here
148 mkdir -p node_modules/mozjpeg/vendor/source
149 cp ${mozjpeg-bin}/vendor/source/mozjpeg.tar.gz node_modules/mozjpeg/vendor/source/
150 (
151 # https://github.com/mozilla/mozjpeg/issues/438
152 substituteInPlace node_modules/mozjpeg/lib/install.js --replace-fail "cmake -DCMAKE" "cmake -DENABLE_STATIC=FALSE -DCMAKE"
153 substituteInPlace node_modules/mozjpeg/lib/install.js --replace-fail "cp cjpeg-static" "cp cjpeg"
154 export LD=$CC
155 export HOME=$(mktemp -d)
156 export YARN_ENABLE_SCRIPTS=1
157 YARN_IGNORE_PATH=1 ${yarn-berry_4.yarn-berry-offline}/bin/yarn config set enableTelemetry false
158 YARN_IGNORE_PATH=1 ${yarn-berry_4.yarn-berry-offline}/bin/yarn config set enableGlobalCache false
159 export npm_config_nodedir="${srcOnly nodejs}"
160 export npm_config_node_gyp="${nodejs}/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js"
161 YARN_IGNORE_PATH=1 ${yarn-berry_4.yarn-berry-offline}/bin/yarn install --inline-builds
162 )
163 yarn webpacker
164 cp -r * ../pip-build/pgadmin4
165 # save some disk space
166 rm -rf ../pip-build/pgadmin4/node_modules
167
168 cd ..
169
170 echo Creating distro config...
171 echo HELP_PATH = \'../../docs/en_US/_build/html/\' > pip-build/pgadmin4/config_distro.py
172 echo MINIFY_HTML = False >> pip-build/pgadmin4/config_distro.py
173
174 echo Creating manifest...
175 echo recursive-include pgadmin4 \* > pip-build/MANIFEST.in
176
177 echo Building wheel...
178 cd pip-build
179 # copy non-standard setup.py to local directory
180 # so setuptools-build-hook can call it
181 cp -v ../pkg/pip/setup_pip.py setup.py
182 '';
183
184 nativeBuildInputs = with pythonPackages; [
185 cython
186 pip
187 sphinx
188 yarn-berry_4
189 yarn-berry_4.yarnBerryConfigHook
190 nodejs
191
192 # for building mozjpeg2
193 cmake
194 autoconf
195 automake
196 libtool
197 nasm
198 pkg-config
199 ];
200
201 buildInputs = [
202 zlib
203 pythonPackages.wheel
204 # for mozjpeg2
205 libpng
206 ];
207
208 propagatedBuildInputs = with pythonPackages; [
209 flask
210 flask-login
211 flask-mail
212 flask-migrate
213 flask-sqlalchemy
214 flask-wtf
215 flask-compress
216 passlib
217 pytz
218 simplejson
219 sqlparse
220 wtforms
221 flask-paranoid
222 psutil
223 psycopg
224 python-dateutil
225 sqlalchemy
226 itsdangerous
227 flask-security
228 bcrypt
229 cryptography
230 sshtunnel
231 ldap3
232 flask-babel
233 gssapi
234 flask-socketio
235 eventlet
236 user-agents
237 wheel
238 authlib
239 qrcode
240 pillow
241 pyotp
242 botocore
243 boto3
244 azure-mgmt-subscription
245 azure-mgmt-rdbms
246 azure-mgmt-resource
247 azure-identity
248 sphinxcontrib-youtube
249 dnspython
250 google-auth-oauthlib
251 google-api-python-client
252 keyring
253 typer
254 rich
255 jsonformatter
256 libgravatar
257 setuptools
258 ];
259
260 passthru.tests = {
261 inherit (nixosTests) pgadmin4;
262 };
263
264 nativeCheckInputs = [
265 postgresqlTestHook
266 postgresql
267 pythonPackages.testscenarios
268 pythonPackages.selenium
269 ];
270
271 # sandboxing issues on aarch64-darwin, see https://github.com/NixOS/nixpkgs/issues/198495
272 doCheck = !postgresqlTestHook.meta.broken;
273
274 checkPhase = ''
275 runHook preCheck
276
277 ## Setup ##
278
279 # pgadmin needs a home directory to save the configuration
280 export HOME=$TMPDIR
281 cd pgadmin4
282
283 # set configuration for postgresql test
284 # also ensure Server Mode is set to false. If not, the tests will fail, since pgadmin expects read/write permissions
285 # in /var/lib/pgadmin and /var/log/pgadmin
286 # see https://github.com/pgadmin-org/pgadmin4/blob/fd1c26408bbf154fa455a49ee5c12895933833a3/web/regression/runtests.py#L217-L226
287 cp -v regression/test_config.json.in regression/test_config.json
288 substituteInPlace regression/test_config.json --replace-fail "localhost" "$PGHOST"
289 substituteInPlace regression/runtests.py --replace-fail "builtins.SERVER_MODE = None" "builtins.SERVER_MODE = False"
290
291 ## Browser test ##
292 python regression/runtests.py --pkg browser --exclude ${skippedTests}
293
294 ## Reverse engineered SQL test ##
295 python regression/runtests.py --pkg resql
296
297 runHook postCheck
298 '';
299
300 meta = {
301 description = "Administration and development platform for PostgreSQL${
302 lib.optionalString (!server-mode) ". Desktop Mode"
303 }";
304 longDescription = ''
305 pgAdmin 4 is designed to meet the needs of both novice and experienced Postgres users alike,
306 providing a powerful graphical interface that simplifies the creation, maintenance and use of database objects.
307 ${
308 if server-mode then
309 ''
310 This version is build with SERVER_MODE set to True (the default). It will require access to `/var/lib/pgadmin`
311 and `/var/log/pgadmin`. This is the default version for the NixOS module `services.pgadmin`.
312 This should NOT be used in combination with the `pgadmin4-desktopmode` package as they will interfere.
313 ''
314 else
315 ''
316 This version is build with SERVER_MODE set to False. It will require access to `~/.pgadmin/`. This version is suitable
317 for single-user deployment or where access to `/var/lib/pgadmin` cannot be granted or the NixOS module cannot be used (e.g. on MacOS).
318 This should NOT be used in combination with the NixOS module `pgadmin` as they will interfere.
319 ''
320 }
321 '';
322 homepage = "https://www.pgadmin.org/";
323 license = lib.licenses.mit;
324 changelog = "https://www.pgadmin.org/docs/pgadmin4/latest/release_notes_${lib.versions.major version}_${lib.versions.minor version}.html";
325 maintainers = with lib.maintainers; [ gador ];
326 mainProgram = "pgadmin4";
327 platforms = lib.platforms.unix;
328 };
329}