Unverified Commit a8c7c8e1 authored by phanirithvij's avatar phanirithvij
Browse files

pdfding: init at 1.4.1

parent 80ab8868
Loading
Loading
Loading
Loading
+87 −0
Original line number Diff line number Diff line
{
  stdenv,
  nodejs,
  npmHooks,
  fetchpatch2,
  fetchNpmDeps,
  fetchzip,
  fetchFromGitHub,
  tailwindcss_4,
}:
let
  pdfjsVersion = "5.4.296"; # see update script
  pdfjsHash = "sha256-b4W7wETq2CIZm2rJCmXEYvPhQtCbXS76L7GDvng6wn4=";
  pdfjs = fetchzip {
    url = "https://github.com/mozilla/pdf.js/releases/download/v${pdfjsVersion}/pdfjs-${pdfjsVersion}-dist.zip";
    hash = pdfjsHash;
    stripRoot = false;
    postFetch = ''
      rm -rf $out/web/locale \
      $out/web/standard_fonts \
      $out/web/compressed.tracemonkey-pldi-09.pdf

      # remove source maps
      find "$out" -name '*.map' -exec rm -f '{}' \;
    '';
  };
in
stdenv.mkDerivation (finalAttrs: {
  pname = "pdfding-frontend";
  version = "1.4.1";
  src = fetchFromGitHub {
    owner = "mrmn2";
    repo = "PdfDing";
    tag = "v${finalAttrs.version}";
    hash = "sha256-8e80gMdB6U3977dIU7bIAAEguYmi+AWQgUgYPDLCYLI=";
  };

  npmDeps = fetchNpmDeps {
    inherit (finalAttrs) src;
    name = "pdfding-frontend-${finalAttrs.version}-npm-deps";
    hash = "sha256-v1NFqDnFcRK8sd0bV3ck+LLMYQ90Dl1R1OnBTwWUVUg=";
  };

  patches = [
    # remove patch in 1.4.2
    # package.json has missing version and name
    (fetchpatch2 {
      url = "https://github.com/mrmn2/PdfDing/pull/203.patch?full_index=1";
      hash = "sha256-lKtpqKdyoGZdU4fTegto+YUIduIWbM82RQU9459NpC0=";
    })
  ];

  nativeBuildInputs = [
    nodejs
    npmHooks.npmConfigHook
    # it is in package.json and thus node_modules but no cli executable
    tailwindcss_4
  ];

  # keeping the file structure same as upstream to minimise confusion
  buildPhase = ''
    runHook preBuild
    mkdir -p $out/pdfding
    cp -r --no-preserve=mode pdfding/static $out/pdfding/static
    cp -r --no-preserve=mode ${finalAttrs.passthru.pdfjs} $out/pdfding/static/pdfjs

    tailwindcss -i $out/pdfding/static/css/input.css -o $out/pdfding/static/css/tailwind.css --minify
    rm $out/pdfding/static/css/input.css

    for i in build/pdf.mjs build/pdf.sandbox.mjs build/pdf.worker.mjs web/viewer.mjs; \
    do node_modules/terser/bin/terser $out/pdfding/static/pdfjs/$i --compress -o $out/pdfding/static/pdfjs/$i; done

    npm run build

    cp -r pdfding/static/js $out/pdfding/static

    runHook postBuild
  '';

  passthru = {
    inherit pdfjs;
  };

  meta = {
    description = "PdfDing frontend";
  };
})
+214 −0
Original line number Diff line number Diff line
{
  lib,
  python3,
  callPackage,
  fetchFromGitHub,
  fetchpatch2,
  makeWrapper,
}:
let
  python = python3;
in
python.pkgs.buildPythonPackage (finalAttrs: {
  pname = "pdfding";
  version = "1.4.1";
  src = fetchFromGitHub {
    owner = "mrmn2";
    repo = "PdfDing";
    tag = "v${finalAttrs.version}";
    hash = "sha256-rrUaqxDO16NAOic74jeYgN+7Alvo+fIIacJdSOg0hFM=";
    # remove in 1.5.0
    postFetch = "mv $out/{license.txt,LICENSE}";
  };
  pyproject = true;

  patches = [
    # remove all patches in 1.5.0 (next version after 1.4.1)
    # patch to add data_dir
    (fetchpatch2 {
      url = "https://github.com/mrmn2/PdfDing/commit/f4945f2836ca8d972fcee2f00ef1d9cf217bada1.patch?full_index=1";
      hash = "sha256-VGjyIAVi+qd2WZ8FVKKC2ijLinoflO7RmPwIW1/oGcY=";
    })
    # pyproject.toml still has 0.1.1 very old version
    (fetchpatch2 {
      url = "https://github.com/mrmn2/PdfDing/pull/203.patch?full_index=1";
      hash = "sha256-lKtpqKdyoGZdU4fTegto+YUIduIWbM82RQU9459NpC0=";
    })
    # allows customising consume_schedule crontab
    (fetchpatch2 {
      url = "https://github.com/mrmn2/PdfDing/commit/96a13574718e0d27240eee8893fb799a02f24c05.patch?full_index=1";
      hash = "sha256-Stq392rIbsphvaE23GgFWb91KzpD6aOQu9MGDDoaO7s=";
    })
    # allow specifying region for s3 backups
    (fetchpatch2 {
      url = "https://github.com/mrmn2/PdfDing/commit/3e412654f62d83b745111bd1d3587aca1a7739e1.patch?full_index=1";
      hash = "sha256-RQS3yJjrIaViFlm6it6zyRZOn+nTQE8qr8OpY+zYSCY=";
    })
  ];

  # remove supervisor from dependencies
  postPatch = ''
    sed -i 's/supervisor.*$//' pyproject.toml

    substituteInPlace pdfding/backup/tests/test_management.py pdfding/backup/tests/test_tasks.py \
      --replace-fail "Path(__file__).parents[2]" "Path('$PDFDING_OUT_DIR')"
  '';

  dependencies =
    with python.pkgs;
    [
      django
      django-allauth
      django-cleanup
      django-htmx
      gunicorn
      markdown
      minio
      nh3
      psycopg2-binary
      pypdf
      pypdfium2
      python-magic
      qrcode
      rapidfuzz
      ruamel-yaml
      whitenoise
      huey
      pillow
      oauthlib

      # dependecies required for django collectstatic
      requests
      pyjwt
      cryptography
    ]
    ++ qrcode.optional-dependencies.pil
    ++ django-allauth.optional-dependencies.socialaccount;

  build-system = with python.pkgs; [ poetry-core ];

  nativeBuildInputs = [
    makeWrapper
  ];

  optional-dependencies = {
    e2e = with python.pkgs; [
      pytest
      pytest-django
      pytest-playwright
      pytest-rerunfailures # required to retry some flaky e2e tests
    ];
  };

  preBuild = ''
    # remove originals, copy from frontend
    rm -rf pdfding/static
    ln -s ${finalAttrs.passthru.frontend}/pdfding/static pdfding/static

    # staticfiles step requires prod configuration, remove dev.py
    mv pdfding/core/settings/dev.py dev.py.bak

    ${python.pythonOnBuildForHost.interpreter} pdfding/manage.py collectstatic

    # not needed, now we have staticfiles directory
    rm -rf pdfding/static

    # the following is from upstream's Dockerfile

    # remove django md5 hash from filenames of pdfjs as it will mess up the relative imports because of the whitenoise setup
    export PDFJS_PATH="pdfding/staticfiles/pdfjs"
    for file_name in $(find $PDFJS_PATH -type f -not -path "$PDFJS_PATH/web/images/*")
    do
      if [[ $file_name =~ "LICENSE" ]]; then
        new=$(echo "$file_name" | sed -E "s/LICENSE\.[a-zA-Z0-9]{12}/LICENSE/");
      else
        new=$(echo "$file_name" | sed -E "s/\.[a-zA-Z0-9]{12}\./\./");
      fi;
      mv -- "$file_name" "$new";
    done \
    && echo 'Successfully removed hash from pdfjs files'

    echo "VERSION = '${finalAttrs.version}'" > pdfding/core/settings/version.py;
  '';

  env.PDFDING_OUT_DIR = "${placeholder "out"}/${python.sitePackages}/pdfding";

  makeWrapperArgs = [
    "--set-default DATA_DIR /var/lib/pdfding"
    # allow for gunicorn processes to have access to Python packages
    "--prefix PYTHONPATH : "
    "${python.pkgs.makePythonPath finalAttrs.passthru.dependencies}:${finalAttrs.env.PDFDING_OUT_DIR}"
  ];

  postInstall = ''
    mkdir -p $out/bin

    makeWrapper "$PDFDING_OUT_DIR/manage.py" $out/bin/pdfding-manage \
      $makeWrapperArgs

    makeWrapper ${lib.getExe python.pkgs.gunicorn} $out/bin/pdfding-start \
      --add-flags '--bind ''${HOST_IP:-127.0.0.1}:''${HOST_PORT:-8080} core.wsgi:application' \
      $makeWrapperArgs
  '';

  pythonRelaxDeps = [
    "django"
    "django-allauth"
    "huey"
    "minio"
    "pypdf"
    "pypdfium2"
  ];

  nativeCheckInputs = with python.pkgs; [
    pytest-django
    pytestCheckHook
  ];

  # from .github/workflows/tests.yaml
  pytestFlags = [
    "--ignore=e2e"
  ];

  /*
    fix two breaking tests by providing full out path
    AssertionError: Calls not found
    AssertionError: 'add_file_to_minio' does not contain all of ...
  */
  preCheck = ''
    # dev.py is required for tests, restore it
    mv dev.py.bak $PDFDING_OUT_DIR/core/settings/dev.py

    # tests should run in pdfding directory
    pushd pdfding
  '';

  postCheck = ''
    # come out of the pdfding directory
    popd

    # remove dev.py
    rm $PDFDING_OUT_DIR/core/settings/dev.py
  '';

  pythonImportsCheck = [
    "pdfding"
  ];

  passthru = {
    inherit python;
    frontend = callPackage ./frontend.nix { };
    updateScript = ./update.sh;
  };

  meta = {
    changelog = "https://github.com/mrmn2/PdfDing/blob/${finalAttrs.src.rev}/CHANGELOG.md";
    description = "Selfhosted PDF manager, viewer and editor offering a seamless user experience on multiple devices";
    downloadPage = "https://github.com/mrmn2/PdfDing";
    homepage = "https://pdfding.com";
    license = lib.licenses.agpl3Only;
    mainProgram = "pdfding-manage";
    maintainers = with lib.maintainers; [ phanirithvij ];
    teams = with lib.teams; [ ngi ];
  };
})
+53 −0
Original line number Diff line number Diff line
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl jq nix-update gitMinimal prefetch-npm-deps coreutils

set -x
set -eou pipefail

version=$(curl ${GITHUB_TOKEN:+ -H "Authorization: Bearer $GITHUB_TOKEN"} -sL https://api.github.com/repos/mrmn2/PdfDing/releases/latest | jq -r '.tag_name')

if [[ "v${UPDATE_NIX_OLD_VERSION:-}" == "$version" ]]; then
  echo "Already up-to-date, version: $version"
  exit 0
fi

# source hashes
nix-update --version="$version" pdfding
nix-update --version="$version" pdfding.frontend

NIXPKGS_PATH="$(git rev-parse --show-toplevel)"
PACKAGE_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"

TMPDIR="$(mktemp -d)"
trap 'rm -rf "$TMPDIR"' EXIT
cd "$TMPDIR"

src="$(nix-build --no-link "$NIXPKGS_PATH" -A pdfding.src)"
cp "$src"/{package.json,package-lock.json} .

# npmDeps hash
prev_npm_hash="$(
  nix-instantiate "$NIXPKGS_PATH" \
    --eval --json \
    -A pdfding.frontend.npmDeps.hash |
    jq -r .
)"
new_npm_hash="$(prefetch-npm-deps ./package-lock.json)"

sed -i "s|$prev_npm_hash|$new_npm_hash|g" "$PACKAGE_DIR/frontend.nix"

# pdfjs version
pdfjs_version="$(grep 'PDFJS_VERSION=' "$src/Dockerfile" | cut -d'=' -f2)"

sed -i "s|pdfjsVersion = .*;|pdfjsVersion = \"$pdfjs_version\";|" "$PACKAGE_DIR/frontend.nix"

# pdfjs hash
sed -i "s|pdfjsHash = .*;|pdfjsHash = \"sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\";|" "$PACKAGE_DIR/frontend.nix"

set +e
new_pdfjs_hash="$(
  nix-build --no-out-link -A pdfding.frontend.pdfjs "$NIXPKGS_PATH" 2>&1 >/dev/null | grep "got:" | cut -d':' -f2 | sed 's| ||g'
)"
set -e

sed -i "s|\"sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"|\"$new_pdfjs_hash\"|g" "$PACKAGE_DIR/frontend.nix"