anki: remove uv.lock, use nixpkgs versions of python deps

See https://github.com/NixOS/nixpkgs/pull/498089, the hack that was
previously introduced for using upstream's python package versions isn't
acceptable in nixpkgs.

Things seem to work from just running anki with this and clicking
around; if there's more subtle breakages, we'll have to play whackamole
with nixpkgs versions.

This also deletes the `update.sh` script, since that will end up having
to be shaped somewhat differently after this change.
It seems pragmatic to add it back as a followup.
This commit is contained in:
Euan Kemp
2026-03-10 17:02:53 +09:00
parent 608d0cadfe
commit a4c9de5c14
3 changed files with 65 additions and 2919 deletions
+65 -32
View File
@@ -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
-89
View File
@@ -1,89 +0,0 @@
#!/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
File diff suppressed because it is too large Load Diff