diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 4693f11f16b2..1eae82f140c5 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -259,6 +259,8 @@ - `linuxPackages.nvidiaPackages.stable` now defaults to the `production` variant instead of `latest`. +- `paperless-ngx` has been updated to minor version 2.15 which switched the web server from Gunicorn to Granian. If you set Gunicorn specific envs (usually contain GUNICORN) they must be updated. Also `services.paperless.address` no longer accepts a domain name and Granian also does not support listening on unix domain sockets. + - `timescaledb` requires manual upgrade steps. After you run ALTER EXTENSION, you must run [this SQL script](https://github.com/timescale/timescaledb-extras/blob/master/utils/2.15.X-fix_hypertable_foreign_keys.sql). For more details, see the following pull requests [#6797](https://github.com/timescale/timescaledb/pull/6797). PostgreSQL 13 is no longer supported in TimescaleDB v2.16. diff --git a/nixos/modules/services/misc/paperless.nix b/nixos/modules/services/misc/paperless.nix index c1f35526bd9b..b0b64c8e8d24 100644 --- a/nixos/modules/services/misc/paperless.nix +++ b/nixos/modules/services/misc/paperless.nix @@ -21,7 +21,8 @@ let PAPERLESS_MEDIA_ROOT = cfg.mediaDir; PAPERLESS_CONSUMPTION_DIR = cfg.consumptionDir; PAPERLESS_THUMBNAIL_FONT_NAME = defaultFont; - GUNICORN_CMD_ARGS = "--bind=${cfg.address}:${toString cfg.port}"; + GRANIAN_HOST = cfg.address; + GRANIAN_PORT = toString cfg.port; } // lib.optionalAttrs (config.time.timeZone != null) { PAPERLESS_TIME_ZONE = config.time.timeZone; @@ -196,7 +197,7 @@ in address = lib.mkOption { type = lib.types.str; - default = "localhost"; + default = "127.0.0.1"; description = "Web interface address."; }; @@ -539,16 +540,15 @@ in echo "PAPERLESS_SECRET_KEY is empty, refusing to start." exit 1 fi - exec ${cfg.package.python.pkgs.gunicorn}/bin/gunicorn \ - -c ${cfg.package}/lib/paperless-ngx/gunicorn.conf.py paperless.asgi:application + exec ${lib.getExe cfg.package.python.pkgs.granian} --interface asginl --ws "paperless.asgi:application" ''; serviceConfig = defaultServiceConfig // { User = cfg.user; Restart = "on-failure"; LimitNOFILE = 65536; - # gunicorn needs setuid, liblapack needs mbind - SystemCallFilter = defaultServiceConfig.SystemCallFilter ++ [ "@setuid mbind" ]; + # liblapack needs mbind + SystemCallFilter = defaultServiceConfig.SystemCallFilter ++ [ "mbind" ]; # Needs to serve web page PrivateNetwork = false; }; diff --git a/pkgs/by-name/pa/paperless-ngx/package.nix b/pkgs/by-name/pa/paperless-ngx/package.nix index 969e9c651d71..7cd092dadee2 100644 --- a/pkgs/by-name/pa/paperless-ngx/package.nix +++ b/pkgs/by-name/pa/paperless-ngx/package.nix @@ -2,8 +2,7 @@ lib, stdenv, fetchFromGitHub, - fetchpatch, - buildNpmPackage, + node-gyp, nodejs_20, nixosTests, gettext, @@ -18,6 +17,7 @@ qpdf, tesseract5, unpaper, + pnpm, poppler-utils, liberation_ttf, xcbuild, @@ -27,23 +27,15 @@ xorg, }: let - version = "2.14.7"; + version = "2.15.1"; src = fetchFromGitHub { owner = "paperless-ngx"; repo = "paperless-ngx"; tag = "v${version}"; - hash = "sha256-p3eUEb/ZPK11NbqE4LU+3TE1Xny9sjfYvVVmABkoAEQ="; + hash = "sha256-vICkRfVxzQlqhSBCieVNSGeXb6FCOx0qOnInKMy6Lhg="; }; - patches = [ - # Fix frontend tests in March (yes, it's date dependent) - (fetchpatch { - url = "https://github.com/paperless-ngx/paperless-ngx/commit/bc90ccc5551f184a683128def772652ad74c65e3.patch"; - hash = "sha256-KArPyKZLi5LfaTDTY3DxA3cdQYYadpQo052Xk9eH14c="; - }) - ]; - # subpath installation is broken with uvicorn >= 0.26 # https://github.com/NixOS/nixpkgs/issues/298719 # https://github.com/paperless-ngx/paperless-ngx/issues/5494 @@ -60,16 +52,6 @@ let # tesseract5 may be overwritten in the paperless module and we need to propagate that to make the closure reduction effective ocrmypdf = prev.ocrmypdf.override { tesseract = tesseract5; }; - - uvicorn = prev.uvicorn.overridePythonAttrs (_: { - version = "0.25.0"; - src = fetchFromGitHub { - owner = "encode"; - repo = "uvicorn"; - rev = "0.25.0"; - hash = "sha256-ng98DTw49zyFjrPnEwfnPfONyjKKZYuLl0qduxSppYk="; - }; - }); }; }; @@ -85,73 +67,91 @@ let poppler-utils ]; - frontend = buildNpmPackage { - pname = "paperless-ngx-frontend"; - inherit version src patches; + frontend = + let + frontendSrc = src + "/src-ui"; + in + stdenv.mkDerivation rec { + pname = "paperless-ngx-frontend"; + inherit version; - nodejs = nodejs_20; # does not build with 22 + src = frontendSrc; - postPatch = '' - cd src-ui - ''; + pnpmDeps = pnpm.fetchDeps { + inherit pname version src; + hash = "sha256-yoTXlxXLcWD2DMxqjb02ZORJ+E0xE1DbZm1VL7vXM4g="; + }; - npmDepsHash = "sha256-hK7Soop9gBZP4m2UzbEIAsLkPKpbQkLmVruY2So4CSs="; + nativeBuildInputs = + [ + node-gyp + nodejs_20 + pkg-config + pnpm.configHook + python3 + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ + xcbuild + ]; - nativeBuildInputs = - [ - pkg-config - python3 - ] - ++ lib.optionals stdenv.hostPlatform.isDarwin [ - xcbuild - ]; + buildInputs = + [ + pango + ] + ++ lib.optionals stdenv.hostPlatform.isDarwin [ + giflib + darwin.apple_sdk.frameworks.CoreText + ]; - buildInputs = - [ - pango - ] - ++ lib.optionals stdenv.hostPlatform.isDarwin [ - giflib - darwin.apple_sdk.frameworks.CoreText - ]; + CYPRESS_INSTALL_BINARY = "0"; + NG_CLI_ANALYTICS = "false"; - CYPRESS_INSTALL_BINARY = "0"; - NG_CLI_ANALYTICS = "false"; + buildPhase = '' + runHook preBuild - npmBuildFlags = [ - "--" - "--configuration" - "production" - ]; + pushd node_modules/canvas + node-gyp rebuild + popd - doCheck = true; - checkPhase = '' - runHook preCheck - npm run test - runHook postCheck - ''; + pnpm run build --configuration production - installPhase = '' - runHook preInstall - mkdir -p $out/lib/paperless-ui - mv ../src/documents/static/frontend $out/lib/paperless-ui/ - runHook postInstall - ''; - }; + runHook postBuild + ''; + + doCheck = true; + checkPhase = '' + runHook preCheck + + pnpm run test + + runHook postCheck + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/lib/paperless-ui + mv ../src/documents/static/frontend $out/lib/paperless-ui/ + + runHook postInstall + ''; + }; in python.pkgs.buildPythonApplication rec { pname = "paperless-ngx"; - pyproject = false; + pyproject = true; - inherit version src patches; + inherit version src; postPatch = '' # pytest-xdist with to many threads makes the tests flaky if (( $NIX_BUILD_CORES > 4)); then NIX_BUILD_CORES=4 fi - substituteInPlace src/setup.cfg \ - --replace-fail "--numprocesses auto --maxprocesses=16" "--numprocesses $NIX_BUILD_CORES" + substituteInPlace pyproject.toml \ + --replace-fail '"--numprocesses=auto",' "" \ + --replace-fail '--maxprocesses=16' "--numprocesses=$NIX_BUILD_CORES" \ + --replace-fail "djangorestframework-guardian~=0.3.0" "djangorestframework-guardian2" ''; nativeBuildInputs = [ @@ -159,6 +159,13 @@ python.pkgs.buildPythonApplication rec { xorg.lndir ]; + pythonRelaxDeps = [ + "django-allauth" + "drf-spectacular-sidecar" + # TODO: https://github.com/NixOS/nixpkgs/pull/373099 + "zxing-cpp" + ]; + dependencies = with python.pkgs; [ @@ -180,11 +187,13 @@ python.pkgs.buildPythonApplication rec { django-soft-delete djangorestframework djangorestframework-guardian2 + drf-spectacular + drf-spectacular-sidecar drf-writable-nested filelock flower gotenberg-client - gunicorn + granian httpx-oauth imap-tools inotifyrecursive @@ -208,16 +217,14 @@ python.pkgs.buildPythonApplication rec { setproctitle tika-client tqdm - uvicorn watchdog whitenoise - whoosh + whoosh-reloaded zxing-cpp ] ++ django-allauth.optional-dependencies.mfa ++ django-allauth.optional-dependencies.socialaccount - ++ redis.optional-dependencies.hiredis - ++ uvicorn.optional-dependencies.standard; + ++ redis.optional-dependencies.hiredis; postBuild = '' # Compile manually because `pythonRecompileBytecodeHook` only works @@ -239,7 +246,7 @@ python.pkgs.buildPythonApplication rec { runHook preInstall mkdir -p $out/lib/paperless-ngx/static/frontend - cp -r {src,static,LICENSE,gunicorn.conf.py} $out/lib/paperless-ngx + cp -r {src,static,LICENSE} $out/lib/paperless-ngx lndir -silent ${frontend}/lib/paperless-ui/frontend $out/lib/paperless-ngx/static/frontend chmod +x $out/lib/paperless-ngx/src/manage.py makeWrapper $out/lib/paperless-ngx/src/manage.py $out/bin/paperless-ngx \