Unverified Commit a955b38b authored by dotlambda's avatar dotlambda Committed by GitHub
Browse files

anki: remove uv.lock, use nixpkgs versions of python deps (#498788)

parents 890e6195 a4c9de5c
Loading
Loading
Loading
Loading
+65 −32
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@
  writableTmpDirAsHomeHook,
  cargo,
  fetchFromGitHub,
  fetchurl,
  installShellFiles,
  lame,
  mpv-unwrapped,
@@ -44,10 +43,57 @@ let
  srcHash = "sha256-0hLTQR7f7s58DUgAZbDeREMee6VrqAKHyhS1Hs/Em1A=";
  cargoHash = "sha256-qcB+r9VzBz6ACZaXPL26MOxxtb/h2OIuxyc54vUgfPM=";
  yarnHash = "sha256-EmKeHORr/+qsDzAwtearMi7qodcCgjeAQcy+79HL7Vg=";
  pythonDeps = map (meta: {
    url = meta.url;
    path = toString (fetchurl meta);
  }) (lib.importJSON ./uv-deps.json);
  pythonDeps = with python3Packages; [
    # anki (pylib) runtime deps
    decorator
    distro
    markdown
    orjson
    protobuf
    requests
    typing-extensions

    # aqt runtime deps
    beautifulsoup4
    flask
    flask-cors
    jsonschema
    pip-system-certs
    pyqt6
    pyqt6-sip
    pyqt6-webengine
    send2trash
    waitress

    # build-system deps (needed by uv for editable installs)
    editables
    hatchling
    pathspec
    pluggy
    setuptools
    trove-classifiers

    # transitive deps
    attrs
    blinker
    certifi
    charset-normalizer
    click
    idna
    itsdangerous
    jinja2
    jsonschema-specifications
    markupsafe
    packaging
    pip
    pysocks
    referencing
    rpds-py
    soupsieve
    urllib3
    werkzeug
    wrapt
  ];

  src = fetchFromGitHub {
    owner = "ankitects";
@@ -82,23 +128,8 @@ let
    installCommand = ''
      #!${stdenv.shell}
      mkdir -p $out
      # note: uv.lock doesn't contain build deps?? https://github.com/astral-sh/uv/issues/5190
      # link them in manually
      ln -vsf ${python3Packages.setuptools.dist}/*.whl $out
      ln -vsf ${python3Packages.editables.dist}/*.whl $out
      # we also force nixpkgs pyqt6 stuff because that needs to match the
      # nixpkgs qt6 version, otherwise we get linker errors
      ln -vsf ${python3Packages.pyqt6.dist}/*.whl $out
      ln -vsf ${python3Packages.pyqt6-webengine.dist}/*.whl $out
      ln -vsf ${python3Packages.pyqt6-sip.dist}/*.whl $out
    ''
    + (lib.strings.concatStringsSep "\n" (
      map (dep: ''
        if ! [[ "${baseNameOf dep.url}" =~ (PyQt|pyqt) ]]; then
          ln -vsf ${dep.path} "$out/${baseNameOf dep.url}"
        fi
      '') pythonDeps
    ));
    + (lib.strings.concatStringsSep "\n" (map (dep: "ln -vsf ${dep.dist}/*.whl $out") pythonDeps));
  } "bash $installCommandPath";
in

@@ -139,6 +170,7 @@ python3Packages.buildPythonApplication rec {
    jq
    ninja
    nodejs
    python3Packages.mypy-protobuf
    qt6.wrapQtAppsHook
    rsync
    rustPlatform.cargoSetupHook
@@ -204,26 +236,27 @@ python3Packages.buildPythonApplication rec {
    echo ${python3.version} > .python-version

    # Setup the python environment.
    # We have 'UV_FIND_LINKS' set, so packages generally should just get picked
    # up, so install everything anki wants.
    # Note, for pyqt stuff, our versions may not match (see the comment above
    # uvWheels), so we don't install those.
    # We use nixpkgs python packages (via UV_FIND_LINKS), whose versions may
    # differ from the uv.lock pins. Strip version constraints so uv accepts
    # whatever version is available.
    strip_versions() { sed 's/==[0-9][^ ;]*//g'; }
    mkdir -p ./out/pyenv
    uv export > requirements.txt
    uv export --no-dev | strip_versions > requirements.txt
    uv pip install --prefix ./out/pyenv -r requirements.txt
    # pyqt6-qt6 and pyqt6-webengine-qt6 are C++ Qt runtimes provided by the
    # system, not Python packages, so exclude them from resolution.
    uv export --project qt --extra qt --extra audio \
      --no-emit-package "pyqt6" \
      --no-emit-package "pyqt6-qt6" \
      --no-emit-package "pyqt6-webengine" \
      --no-emit-package "pyqt6-webengine-qt6" \
      --no-emit-package "pyqt6-sip" \
      > requirements.txt
      | strip_versions > requirements.txt
    uv pip install --prefix ./out/pyenv -r requirements.txt
    uv export --project pylib > requirements.txt
    uv export --project pylib | strip_versions > requirements.txt
    uv pip install --prefix ./out/pyenv -r requirements.txt

    # anki's build tooling expects python in there too
    # anki's build tooling expects python and protoc-gen-mypy in pyenv
    mkdir -p ./out/pyenv/bin
    ln -sf $PYTHON_BINARY ./out/pyenv/bin/python
    ln -sf ${lib.getExe python3Packages.mypy-protobuf} ./out/pyenv/bin/protoc-gen-mypy

    mv node_modules out

pkgs/by-name/an/anki/update.sh

deleted100755 → 0
+0 −89
Original line number Diff line number Diff line
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl git wget jq common-updater-scripts yarn-berry_4 yarn-berry_4.yarn-berry-fetcher tomlq nix-prefetch-github

set -eu -o pipefail
set -x

TMPDIR=/tmp/anki-update-script

cleanup() {
  if [ -e $TMPDIR/.done ]; then
    rm -rf "$TMPDIR"
  else
    echo
    read -p "Script exited prematurely. Do you want to delete the temporary directory $TMPDIR ? " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
      rm -rf "$TMPDIR"
    fi
  fi
}

trap cleanup EXIT

if [[ "$#" > 0 ]]; then
  tag="$1"
else
  tag="$(curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s 'https://api.github.com/repos/ankitects/anki/releases' | jq -r  'map(select(.prerelease == false)) | .[0].tag_name')"
fi
tag_sha="$(curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s "https://api.github.com/repos/ankitects/anki/git/ref/tags/$tag" | jq -r '.object.sha')"
rev="$(curl ${GITHUB_TOKEN:+" -u \":$GITHUB_TOKEN\""} -s "https://api.github.com/repos/ankitects/anki/git/tags/$tag_sha" | jq -r '.object.sha')"

nixpkgs="$(git rev-parse --show-toplevel)"
scriptDir="$nixpkgs/pkgs/by-name/an/anki"

ver=$(nix-instantiate --eval -E "(import \"$nixpkgs\" { config = {}; overlays = []; }).anki.version" | tr -d '"')

if [[ "$tag" == "$ver" ]]; then
  echo "Latest version is $tag, already $ver, skipping update"
  exit 0
fi
echo "Updating from $ver to $tag"

mkdir -p $TMPDIR

curl -o $TMPDIR/yarn.lock "https://raw.githubusercontent.com/ankitects/anki/refs/tags/$tag/yarn.lock"

echo "Generating missing-hashes.json"
yarn-berry-fetcher missing-hashes $TMPDIR/yarn.lock > $TMPDIR/missing-hashes.json
yarnHash=$(yarn-berry-fetcher prefetch $TMPDIR/yarn.lock $TMPDIR/missing-hashes.json)

echo "Copying missing-hashes.json back into nixpkgs"
cp $TMPDIR/missing-hashes.json "$scriptDir/missing-hashes.json"

sed -i -E "s|yarnHash = \".*\"|yarnHash = \"$yarnHash\"|" "$scriptDir/package.nix"

echo "yarnHash updated"
echo "Regenerating uv-deps.json"

curl -o $TMPDIR/uv.lock "https://raw.githubusercontent.com/ankitects/anki/refs/tags/$tag/uv.lock"

# Extract all urls to pre-compute hashes so we can download whatever uv needs for its cache.
# We skip pyqt because the derivation uses the nixos packaged ones for
# native-library compatibility.
tq -f $TMPDIR/uv.lock --output json '.' | jq '.. | objects | .url | select(. != null)' -cr | \
  grep -Ev "PyQt|pyqt" \
  > $TMPDIR/uv.urls

echo '[' > $TMPDIR/uv-deps.json
for url in $(cat $TMPDIR/uv.urls); do
  urlHash="$(nix-prefetch-url --type sha256 "$url")"
  echo '{"url": "'$url'", "hash": "'$(nix-hash --type sha256 --to-sri $urlHash)'"},' >> $TMPDIR/uv-deps.json
done
# strip final trailing comma
sed '$s/,$//' -i $TMPDIR/uv-deps.json
echo ']' >> $TMPDIR/uv-deps.json

# and jq format it on the way into nixpkgs too
jq '.' $TMPDIR/uv-deps.json > "$scriptDir/uv-deps.json"
echo "Wrote uv-deps.json"

# github as well

srcHash="$(nix-prefetch-github ankitects anki --fetch-submodules --rev "$tag" --json | jq -r '.hash')"

sed -i "s|version = \".*\";|version = \"$tag\";|" "$scriptDir/package.nix"
sed -i "s|rev = \".*\";|rev = \"$rev\";|" "$scriptDir/package.nix"
sed -i "s|srcHash = \".*\";|srcHash = \"$srcHash\";|" "$scriptDir/package.nix"

touch $TMPDIR/.done

pkgs/by-name/an/anki/uv-deps.json

deleted100644 → 0
+0 −2798

File deleted.

Preview size limit exceeded, changes collapsed.