Skip to content

Commit ae2cb2c

Browse files
committed
Add Docker script to run build_nix and update default.nix comments #339
Signed-off-by: Chin Yeung Li <[email protected]>
1 parent dc303a0 commit ae2cb2c

File tree

2 files changed

+149
-114
lines changed

2 files changed

+149
-114
lines changed

build_nix_docker.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Use Docker container to run nix-build.
4+
Using Docker approach to ensure a consistent and isolated build environment.
5+
6+
To run the script:
7+
8+
python build_nix_docker.py
9+
10+
This script will run nix-build and place the built results in the
11+
dist/nix/ directory, it will then run nix-collect-garbage for cleanup.
12+
"""
13+
14+
import os
15+
import shutil
16+
import subprocess
17+
import sys
18+
from pathlib import Path
19+
20+
21+
def cleanup_nix_store():
22+
"""
23+
Remove the nix-store volume to ensure clean state
24+
"""
25+
try:
26+
subprocess.run(['docker', 'volume', 'rm', 'nix-store'],
27+
check=True, capture_output=True)
28+
print("Cleaned up nix-store volume.")
29+
except subprocess.CalledProcessError as e:
30+
# Volume might not exist, which is fine
31+
if "no such volume" not in e.stderr.decode().lower():
32+
print(f"Warning: Could not remove nix-store volume: {e.stderr.decode()}")
33+
pass
34+
35+
36+
def build_nix_with_docker():
37+
# Create output directory
38+
output_dir = Path('dist/nix')
39+
output_dir.mkdir(parents=True, exist_ok=True)
40+
41+
docker_cmd = [
42+
'docker', 'run', '--rm',
43+
'-v', f"{os.getcwd()}:/workspace",
44+
'-v', 'nix-store:/nix',
45+
'-w', '/workspace',
46+
'nixos/nix',
47+
'/bin/sh', '-c',
48+
f"""set -ex
49+
# Update nix-channel to get latest packages
50+
nix-channel --update
51+
52+
# Run nix-build
53+
nix-build default.nix -o result
54+
55+
# Check if build was successful
56+
if [ -d result ]; then
57+
# Copy the build result to dist/nix/
58+
mkdir -p /workspace/dist/nix
59+
# Use nix-store to get the actual store path
60+
STORE_PATH=$(readlink result)
61+
cp -r "$STORE_PATH"/* /workspace/dist/nix/ || true
62+
63+
# Also copy the symlink target directly if directory copy fails
64+
if [ ! "$(ls -A /workspace/dist/nix/)" ]; then
65+
# If directory is empty, try to copy the store path itself
66+
cp -r "$STORE_PATH" /workspace/dist/nix/store_result || true
67+
fi
68+
69+
# Remove the result symlink
70+
rm -f result
71+
72+
# Run garbage collection to clean up
73+
nix-collect-garbage -d
74+
75+
else
76+
echo "Error: nix-build failed - result directory not found" >&2
77+
exit 1
78+
fi
79+
"""
80+
]
81+
82+
try:
83+
subprocess.run(docker_cmd, check=True)
84+
85+
# Verify if the output directory contains any files or
86+
# subdirectories.
87+
if any(output_dir.iterdir()):
88+
print(f"\nNix build completed. Results in: {output_dir}")
89+
else:
90+
print(f"Nix build failed.", file=sys.stderr)
91+
92+
except subprocess.CalledProcessError as e:
93+
print(f"Build failed: {e}", file=sys.stderr)
94+
sys.exit(1)
95+
96+
97+
if __name__ == '__main__':
98+
# Check if "docker" is available
99+
if not shutil.which('docker'):
100+
print("Error: Docker not found. Please install Docker first.", file=sys.stderr)
101+
sys.exit(1)
102+
103+
# Check if default.nix exists
104+
if not Path('default.nix').exists():
105+
print("Error: default.nix not found in current directory", file=sys.stderr)
106+
sys.exit(1)
107+
108+
# Clean up the volume to ensure consistent state
109+
cleanup_nix_store()
110+
111+
build_nix_with_docker()

default.nix

Lines changed: 38 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# This file is used by `nix-build`.
2+
# Update it manually whenever the version or dependencies change in `pyproject.toml`.
3+
4+
# For packages with pinned versions to match those in pyproject.toml.
5+
# It's recommended to use pre-built wheels instead of building from source,
6+
# as source builds may require additional dependencies.
7+
8+
# Run the following command to compute the sha256:
9+
# nix-prefetch-url <url>
110
{
211
pkgs ? import <nixpkgs> { },
312
}:
@@ -23,28 +32,22 @@ let
2332
// extraAttrs
2433
);
2534

26-
maturin = pkgs.stdenv.mkDerivation rec {
27-
pname = "maturin";
28-
version = "1.8.6";
29-
30-
src = pkgs.fetchurl {
31-
url = "https://github.com/PyO3/maturin/releases/download/v1.8.6/maturin-x86_64-unknown-linux-musl.tar.gz";
32-
sha256 = "0vxhniz9shj6gy3sxc8d2bdp24z3vjj435sn31mcvr06r1wwgjjm";
33-
};
35+
pythonOverlay = self: super: {
36+
maturin = python.pkgs.buildPythonPackage rec {
37+
pname = "maturin";
38+
version = "1.8.6";
39+
format = "wheel";
3440

35-
# Don't use phases, just unpack directly
36-
unpackPhase = "true";
41+
src = pkgs.fetchurl {
42+
url = "https://files.pythonhosted.org/packages/f9/aa/8090f8b3f5f7ec46bc95deb0f5b29bf52c98156ef594f2e65d20bf94cea1/maturin-1.8.6-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl";
43+
sha256 = "15870w46liwy15a5x81cpdb8f9b6k4sawzxii604r5bmcj699idy";
44+
};
3745

38-
installPhase = ''
39-
mkdir -p $out/bin
40-
# Extract the tarball directly to the bin directory
41-
tar -xzf $src -C $out/bin
42-
# Ensure the binary is executable
43-
chmod +x $out/bin/maturin
44-
'';
45-
};
46+
# Disable checks
47+
doCheck = false;
48+
doInstallCheck = false;
49+
};
4650

47-
pythonOverlay = self: super: {
4851
rq-scheduler = python.pkgs.buildPythonPackage rec {
4952
pname = "rq-scheduler";
5053
version = "0.14.0";
@@ -58,13 +61,6 @@ let
5861
# Disable checks
5962
doCheck = false;
6063
doInstallCheck = false;
61-
62-
# Meta information
63-
meta = with pkgs.lib; {
64-
description = "RQ Scheduler is a small package that adds job scheduling capabilities to RQ, a Redis based Python queuing library.";
65-
license = licenses.mit;
66-
homepage = "https://github.com/rq/rq-scheduler";
67-
};
6864
};
6965

7066
clamd = python.pkgs.buildPythonPackage rec {
@@ -80,13 +76,6 @@ let
8076
# Disable checks
8177
doCheck = false;
8278
doInstallCheck = false;
83-
84-
# Meta information
85-
meta = with pkgs.lib; {
86-
description = "clamd is a portable Python module to use the ClamAV anti-virus engine on Windows, Linux, MacOSX and other platforms.";
87-
license = licenses.lgpl21;
88-
homepage = "https://github.com/graingert/python-clamd";
89-
};
9079
};
9180

9281
mockldap = python.pkgs.buildPythonPackage rec {
@@ -102,13 +91,6 @@ let
10291
# Disable checks
10392
doCheck = false;
10493
doInstallCheck = false;
105-
106-
# Meta information
107-
meta = with pkgs.lib; {
108-
description = "The goal of mockldap is to provide a mock instance of LDAPObject in response to any call to ldap.initialize.";
109-
license = licenses.cc0;
110-
homepage = "https://github.com/psagers/mockldap";
111-
};
11294
};
11395

11496
swapper = python.pkgs.buildPythonPackage rec {
@@ -124,13 +106,6 @@ let
124106
# Disable checks
125107
doCheck = false;
126108
doInstallCheck = false;
127-
128-
# Meta information
129-
meta = with pkgs.lib; {
130-
description = "Swapper is an unofficial API for the undocumented but very powerful Django feature: swappable models.";
131-
license = licenses.mit;
132-
homepage = "https://github.com/openwisp/django-swappable-models";
133-
};
134109
};
135110

136111
django-rest-hooks = python.pkgs.buildPythonPackage rec {
@@ -146,13 +121,6 @@ let
146121
# Disable checks
147122
doCheck = false;
148123
doInstallCheck = false;
149-
150-
# Meta information
151-
meta = with pkgs.lib; {
152-
description = "Forked from zapier/django-rest-hooks.";
153-
license = licenses.isc;
154-
homepage = "https://github.com/aboutcode-org/django-rest-hooks";
155-
};
156124
};
157125

158126
aboutcode-toolkit = python.pkgs.buildPythonPackage rec {
@@ -168,13 +136,6 @@ let
168136
# Disable checks
169137
doCheck = false;
170138
doInstallCheck = false;
171-
172-
# Meta information
173-
meta = with pkgs.lib; {
174-
description = "The AboutCode Toolkit and ABOUT files provide a simple way to document the origin, license, usage and other important or interesting information about third-party software components that you use in your project.";
175-
license = licenses.asl20;
176-
homepage = "https://github.com/aboutcode-org/aboutcode-toolkit";
177-
};
178139
};
179140

180141
django-grappelli = python.pkgs.buildPythonPackage rec {
@@ -190,13 +151,6 @@ let
190151
# Disable checks
191152
doCheck = false;
192153
doInstallCheck = false;
193-
194-
# Meta information
195-
meta = with pkgs.lib; {
196-
description = "A jazzy skin for the Django admin interface.";
197-
license = licenses.bsd3;
198-
homepage = "http://www.grappelliproject.com/";
199-
};
200154
};
201155

202156
django-altcha = python.pkgs.buildPythonPackage rec {
@@ -212,13 +166,6 @@ let
212166
# Disable checks
213167
doCheck = false;
214168
doInstallCheck = false;
215-
216-
# Meta information
217-
meta = with pkgs.lib; {
218-
description = "Django Altcha is a Django library that provides easy integration of Altcha CAPTCHA into your Django forms, enhancing user verification with configurable options.";
219-
license = licenses.mit;
220-
homepage = "https://github.com/aboutcode-org/django-altcha";
221-
};
222169
};
223170

224171
jsonfield = python.pkgs.buildPythonPackage rec {
@@ -234,13 +181,6 @@ let
234181
# Disable checks
235182
doCheck = false;
236183
doInstallCheck = false;
237-
238-
# Meta information
239-
meta = with pkgs.lib; {
240-
description = "jsonfield is a reusable model field that allows you to store validated JSON, automatically handling serialization to and from the database.";
241-
license = licenses.mit;
242-
homepage = "https://github.com/rpkilby/jsonfield/";
243-
};
244184
};
245185

246186
pip = python.pkgs.buildPythonPackage rec {
@@ -256,13 +196,6 @@ let
256196
# Disable checks
257197
doCheck = false;
258198
doInstallCheck = false;
259-
260-
# Meta information
261-
meta = with pkgs.lib; {
262-
description = "The PyPA recommended tool for installing Python packages";
263-
license = licenses.mit;
264-
homepage = "https://pip.pypa.io/";
265-
};
266199
};
267200

268201
psycopg = python.pkgs.buildPythonPackage rec {
@@ -278,13 +211,6 @@ let
278211
# Disable checks
279212
doCheck = false;
280213
doInstallCheck = false;
281-
282-
# Meta information
283-
meta = with pkgs.lib; {
284-
description = "A modern implementation of a PostgreSQL adapter for Python.";
285-
license = licenses.lgpl3;
286-
homepage = "https://www.psycopg.org/";
287-
};
288214
};
289215

290216
django-registration = python.pkgs.buildPythonPackage rec {
@@ -300,13 +226,21 @@ let
300226
# Disable checks
301227
doCheck = false;
302228
doInstallCheck = false;
229+
};
230+
231+
requests = python.pkgs.buildPythonPackage rec {
232+
pname = "requests";
233+
version = "2.32.4";
234+
format = "wheel";
303235

304-
# Meta information
305-
meta = with pkgs.lib; {
306-
description = "This is a user-registration application for Django.";
307-
license = licenses.bsd3;
308-
homepage = "https://github.com/ubernostrum/django-registration";
236+
src = pkgs.fetchurl {
237+
url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl";
238+
sha256 = "0b1bmhqv0xarifclr53icqwpsw1hk3l4w8230jrm0v9av8ybvfi7";
309239
};
240+
241+
# Disable checks
242+
doCheck = false;
243+
doInstallCheck = false;
310244
};
311245

312246
rpds-py = python.pkgs.buildPythonPackage rec {
@@ -322,13 +256,6 @@ let
322256
# Disable checks
323257
doCheck = false;
324258
doInstallCheck = false;
325-
326-
# Meta information
327-
meta = with pkgs.lib; {
328-
description = "Python bindings to the Rust rpds crate for persistent data structures.";
329-
license = licenses.mit;
330-
homepage = "https://github.com/crate-py/rpds";
331-
};
332259
};
333260

334261
django = self.buildPythonPackage rec {
@@ -726,7 +653,6 @@ let
726653
pyyaml = disableAllTests super.pyyaml {};
727654
qrcode = disableAllTests super.qrcode {};
728655
referencing = disableAllTests super.referencing {};
729-
requests = disableAllTests super.requests {};
730656
requests-oauthlib = disableAllTests super.requests-oauthlib {};
731657
restructuredtext-lint = disableAllTests super.restructuredtext-lint {};
732658
rq = disableAllTests super.rq {};
@@ -774,6 +700,7 @@ let
774700
base // custom;
775701
};
776702

703+
777704
pythonApp = pythonWithOverlay.pkgs.buildPythonApplication {
778705
pname = "dejacode";
779706
version = "5.4.0";
@@ -792,13 +719,10 @@ let
792719
pip
793720
];
794721

795-
# maturin is a build tool, not a runtime dependency
796-
# It's only needed during the build phase to compile Rust extensions
797-
# It shouldn't be included in the final Python package's dependencies
798-
# and therefore can be excluded from the final dependencies check
799-
pythonRemoveDeps = ["maturin"];
800722

723+
# Specifies all Python dependencies required at runtime to ensure consistent overrides.
801724
propagatedBuildInputs = with pythonWithOverlay.pkgs; [
725+
maturin
802726
crontab
803727
django-filter
804728
natsort

0 commit comments

Comments
 (0)