anki: add withAddons
`anki.withAddons` creates a wrapped version of Anki with all the addons provided to the function installed.
This commit is contained in:
parent
ebed8fb6dc
commit
a6826b4103
126
pkgs/games/anki/addons/anki-utils.nix
Normal file
126
pkgs/games/anki/addons/anki-utils.nix
Normal file
@ -0,0 +1,126 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
symlinkJoin,
|
||||
lndir,
|
||||
formats,
|
||||
runCommand,
|
||||
}:
|
||||
{
|
||||
buildAnkiAddon = lib.extendMkDerivation {
|
||||
constructDrv = stdenv.mkDerivation;
|
||||
extendDrvArgs =
|
||||
finalAttrs:
|
||||
{
|
||||
pname,
|
||||
version,
|
||||
src,
|
||||
sourceRoot ? "",
|
||||
configurePhase ? ''
|
||||
runHook preConfigure
|
||||
runHook postConfigure
|
||||
'',
|
||||
buildPhase ? ''
|
||||
runHook preBuild
|
||||
runHook postBuild
|
||||
'',
|
||||
dontPatchELF ? true,
|
||||
dontStrip ? true,
|
||||
nativeBuildInputs ? [ ],
|
||||
passthru ? { },
|
||||
meta ? { },
|
||||
# Script run after "user_files" folder is populated.
|
||||
# Used when an add-on needs to process and change "user_files" based
|
||||
# on what the user added to it.
|
||||
processUserFiles ? "",
|
||||
...
|
||||
}:
|
||||
{
|
||||
inherit
|
||||
version
|
||||
src
|
||||
sourceRoot
|
||||
configurePhase
|
||||
buildPhase
|
||||
dontPatchELF
|
||||
dontStrip
|
||||
nativeBuildInputs
|
||||
;
|
||||
|
||||
pname = "anki-addon-${pname}";
|
||||
|
||||
installPrefix = "share/anki/addons/${pname}";
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p "$out/$installPrefix"
|
||||
find . -mindepth 1 -maxdepth 1 | xargs -d'\n' mv -t "$out/$installPrefix/"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
passthru = {
|
||||
withConfig =
|
||||
{
|
||||
# JSON add-on config. The available options for an add-on are in its
|
||||
# config.json file.
|
||||
# See https://addon-docs.ankiweb.net/addon-config.html#config-json
|
||||
config ? { },
|
||||
# Path to a folder to be merged with the add-on "user_files" folder.
|
||||
# See https://addon-docs.ankiweb.net/addon-config.html#user-files.
|
||||
userFiles ? null,
|
||||
}:
|
||||
let
|
||||
metaConfigFormat = formats.json { };
|
||||
addonMetaConfig = metaConfigFormat.generate "meta.json" { inherit config; };
|
||||
in
|
||||
symlinkJoin {
|
||||
pname = "${finalAttrs.pname}-with-config";
|
||||
inherit (finalAttrs) version meta;
|
||||
|
||||
paths = [
|
||||
finalAttrs.finalPackage
|
||||
];
|
||||
|
||||
postBuild = ''
|
||||
cd $out/${finalAttrs.installPrefix}
|
||||
|
||||
rm -f meta.json
|
||||
ln -s ${addonMetaConfig} meta.json
|
||||
|
||||
mkdir -p user_files
|
||||
${
|
||||
if (userFiles != null) then
|
||||
''
|
||||
${lndir}/bin/lndir -silent "${userFiles}" user_files
|
||||
''
|
||||
else
|
||||
""
|
||||
}
|
||||
|
||||
${processUserFiles}
|
||||
'';
|
||||
};
|
||||
} // passthru;
|
||||
|
||||
meta = {
|
||||
platforms = lib.platforms.all;
|
||||
} // meta;
|
||||
};
|
||||
};
|
||||
|
||||
buildAnkiAddonsDir =
|
||||
addonPackages:
|
||||
let
|
||||
addonDirs = map (pkg: "${pkg}/share/anki/addons") addonPackages;
|
||||
addons = lib.concatMapStringsSep " " (p: "${p}/*") addonDirs;
|
||||
in
|
||||
runCommand "anki-addons" { } ''
|
||||
mkdir $out
|
||||
[[ '${addons}' ]] || exit 0
|
||||
for addon in ${addons}; do
|
||||
ln -s "$addon" $out/
|
||||
done
|
||||
'';
|
||||
}
|
6
pkgs/games/anki/addons/default.nix
Normal file
6
pkgs/games/anki/addons/default.nix
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
callPackage,
|
||||
}:
|
||||
{
|
||||
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
lame,
|
||||
mpv-unwrapped,
|
||||
ninja,
|
||||
callPackage,
|
||||
nixosTests,
|
||||
nodejs,
|
||||
nodejs-slim,
|
||||
@ -129,6 +130,8 @@ python3.pkgs.buildPythonApplication {
|
||||
./patches/disable-auto-update.patch
|
||||
./patches/remove-the-gl-library-workaround.patch
|
||||
./patches/skip-formatting-python-code.patch
|
||||
# Used in with-addons.nix
|
||||
./patches/allow-setting-addons-folder.patch
|
||||
];
|
||||
|
||||
inherit cargoDeps yarnOfflineCache;
|
||||
@ -301,6 +304,7 @@ python3.pkgs.buildPythonApplication {
|
||||
'';
|
||||
|
||||
passthru = {
|
||||
withAddons = ankiAddons: callPackage ./with-addons.nix { inherit ankiAddons; };
|
||||
tests.anki-sync-server = nixosTests.anki-sync-server;
|
||||
};
|
||||
|
||||
@ -324,6 +328,7 @@ python3.pkgs.buildPythonApplication {
|
||||
inherit (mesa.meta) platforms;
|
||||
maintainers = with maintainers; [
|
||||
euank
|
||||
junestepp
|
||||
oxij
|
||||
];
|
||||
# Reported to crash at launch on darwin (as of 2.1.65)
|
||||
|
15
pkgs/games/anki/patches/allow-setting-addons-folder.patch
Normal file
15
pkgs/games/anki/patches/allow-setting-addons-folder.patch
Normal file
@ -0,0 +1,15 @@
|
||||
diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py
|
||||
index 469908c1b2..34612d6e08 100644
|
||||
--- a/qt/aqt/profiles.py
|
||||
+++ b/qt/aqt/profiles.py
|
||||
@@ -310,7 +310,9 @@ def profileFolder(self, create: bool = True) -> str:
|
||||
return path
|
||||
|
||||
def addonFolder(self) -> str:
|
||||
- return self._ensureExists(os.path.join(self.base, "addons21"))
|
||||
+ path = Path(os.environ.get("ANKI_ADDONS") or Path(self.base) / "addons21")
|
||||
+ path.mkdir(parents=True, exist_ok=True)
|
||||
+ return str(path.resolve())
|
||||
|
||||
def backupFolder(self) -> str:
|
||||
return self._ensureExists(os.path.join(self.profileFolder(), "backups"))
|
107
pkgs/games/anki/with-addons.nix
Normal file
107
pkgs/games/anki/with-addons.nix
Normal file
@ -0,0 +1,107 @@
|
||||
{
|
||||
lib,
|
||||
symlinkJoin,
|
||||
makeWrapper,
|
||||
anki,
|
||||
anki-utils,
|
||||
writeTextDir,
|
||||
ankiAddons ? [ ],
|
||||
}:
|
||||
/*
|
||||
`ankiAddons`
|
||||
: A set of Anki add-ons to be installed. Here's a an example:
|
||||
|
||||
~~~
|
||||
pkgs.anki.withAddons [
|
||||
# When the add-on is already available in nixpkgs
|
||||
pkgs.ankiAddons.anki-connect
|
||||
|
||||
# When the add-on is not available in nixpkgs
|
||||
(pkgs.anki-utils.buildAnkiAddon (finalAttrs: {
|
||||
pname = "recolor";
|
||||
version = "3.1";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "AnKing-VIP";
|
||||
repo = "AnkiRecolor";
|
||||
rev = finalAttrs.version;
|
||||
sparseCheckout = [ "src/addon" ];
|
||||
hash = "sha256-28DJq2l9DP8O6OsbNQCZ0pm4S6CQ3Yz0Vfvlj+iQw8Y=";
|
||||
};
|
||||
sourceRoot = "source/src/addon";
|
||||
}))
|
||||
|
||||
# When the add-on needs to be configured
|
||||
pkgs.ankiAddons.passfail2.withConfig {
|
||||
config = {
|
||||
again_button_name = "not quite";
|
||||
good_button_name = "excellent";
|
||||
};
|
||||
|
||||
user_files = ./dir-to-be-merged-into-addon-user-files-dir;
|
||||
};
|
||||
]
|
||||
~~~
|
||||
|
||||
The original `anki` executable will be wrapped so that it uses the addons from
|
||||
`ankiAddons`.
|
||||
|
||||
This only works with Anki versions patched to support the `ANKI_ADDONS` environment
|
||||
variable. `pkgs.anki` has this, but `pkgs.anki-bin` does not.
|
||||
*/
|
||||
let
|
||||
defaultAddons = [
|
||||
(anki-utils.buildAnkiAddon {
|
||||
pname = "nixos";
|
||||
version = "1.0";
|
||||
src = writeTextDir "__init__.py" ''
|
||||
import aqt
|
||||
from aqt.qt import QMessageBox
|
||||
import json
|
||||
|
||||
def addons_dialog_will_show(dialog: aqt.addons.AddonsDialog) -> None:
|
||||
dialog.setEnabled(False)
|
||||
QMessageBox.information(
|
||||
dialog,
|
||||
"NixOS Info",
|
||||
("These add-ons are managed by NixOS.<br>"
|
||||
"See <a href='https://github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix'>"
|
||||
"github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix</a>")
|
||||
)
|
||||
|
||||
def addon_tried_to_write_config(module: str, conf: dict) -> None:
|
||||
message_box = QMessageBox(
|
||||
QMessageBox.Icon.Warning,
|
||||
"NixOS Info",
|
||||
(f"The add-on module: \"{module}\" tried to update its config.<br>"
|
||||
"See <a href='https://github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix'>"
|
||||
"github.com/NixOS/nixpkgs/tree/master/pkgs/games/anki/with-addons.nix</a>"
|
||||
" for how to configure add-ons managed by NixOS.")
|
||||
)
|
||||
message_box.setDetailedText(json.dumps(conf))
|
||||
message_box.exec()
|
||||
|
||||
aqt.gui_hooks.addons_dialog_will_show.append(addons_dialog_will_show)
|
||||
aqt.mw.addonManager.writeConfig = addon_tried_to_write_config
|
||||
'';
|
||||
meta.maintainers = with lib.maintainers; [ junestepp ];
|
||||
})
|
||||
];
|
||||
in
|
||||
symlinkJoin {
|
||||
inherit (anki) version;
|
||||
pname = "${anki.pname}-with-addons";
|
||||
|
||||
paths = [ anki ];
|
||||
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/anki \
|
||||
--set ANKI_ADDONS "${anki-utils.buildAnkiAddonsDir (ankiAddons ++ defaultAddons)}"
|
||||
'';
|
||||
|
||||
meta = builtins.removeAttrs anki.meta [
|
||||
"name"
|
||||
"outputsToInstall"
|
||||
"position"
|
||||
];
|
||||
}
|
@ -14902,6 +14902,8 @@ with pkgs;
|
||||
amoeba-data = callPackage ../games/amoeba/data.nix { };
|
||||
|
||||
anki = callPackage ../games/anki { };
|
||||
anki-utils = callPackage ../games/anki/addons/anki-utils.nix { };
|
||||
ankiAddons = recurseIntoAttrs (callPackage ../games/anki/addons { });
|
||||
anki-bin = callPackage ../games/anki/bin.nix { };
|
||||
anki-sync-server = callPackage ../games/anki/sync-server.nix { };
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user