aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flake.nix22
-rw-r--r--modules/build.nix174
-rw-r--r--modules/default.nix5
-rw-r--r--modules/file.nix41
-rw-r--r--modules/kfmon.nix21
-rw-r--r--modules/kobo.nix53
-rw-r--r--modules/koreader.nix28
-rw-r--r--modules/lib/file.nix43
-rw-r--r--modules/lib/manifest.nix41
-rw-r--r--modules/manifest.nix2
-rw-r--r--modules/nickel.nix25
-rw-r--r--modules/plato.nix58
-rw-r--r--modules/root.nix21
13 files changed, 379 insertions, 155 deletions
diff --git a/flake.nix b/flake.nix
index 0a165b9..a79a9e7 100644
--- a/flake.nix
+++ b/flake.nix
@@ -11,14 +11,6 @@
overlays.default = import ./overlays;
- # koboConfigurations.default = self.lib.koboConfiguration {
- # pkgs = import nixpkgs {
- # system = "x86_64-linux";
- # overlays = builtins.attrValues self.overlays;
- # };
- # modules = [ ./config ];
- # };
-
} // flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
@@ -30,14 +22,16 @@
modules = [ ./config ];
};
in {
+
packages = {
- default = myKobo.config.kobo.package;
- installer = myKobo.config.installer.package;
+ default = myKobo.config.build.src;
+ # installer = myKobo.config.installer.package;
};
- apps = {
- type = "app";
- program = "${pkgs.lib.getExe myKobo.config.installer.package} ${myKobo.config.kobo.package}";
- };
+ # apps = {
+ # type = "app";
+ # program = "${pkgs.lib.getExe myKobo.config.installer.package} ${myKobo.config.kobo.src}";
+ # };
+
});
}
diff --git a/modules/build.nix b/modules/build.nix
new file mode 100644
index 0000000..dfff338
--- /dev/null
+++ b/modules/build.nix
@@ -0,0 +1,174 @@
+{ config, pkgs, lib, ... }:
+with builtins // lib;
+let
+ cfg = config.build;
+
+ copyFileFunc = ''
+ function copyFile() {
+ local SOURCE="$1"
+ local RELTARGET="$2"
+ local EXECUTABLE="3"
+
+ local TARGET
+ TARGET="$(realpath -m "$REALOUT/$RELTARGET")"
+ if [[ ! $TARGET == $REALOUT* ]]; then
+ echo "Error installing file $RELTARGET outside of kobo src" >&2
+ exit 1
+ fi
+
+ mkdir -pv "$(dirname "$TARGET")"
+ if [[ -d "$SOURCE" ]]; then
+ if [[ -d "$TARGET" ]]; then
+ cp -rfv "$SOURCE/." "$TARGET/"
+ else
+ cp -rfv "$SOURCE" "$TARGET"
+ fi
+ else
+ cp -fv "$SOURCE" "$TARGET"
+ fi
+
+ if [[ "$EXECUTABLE" == "inherit" ]]; then
+ :
+ elif [[ "$EXECUTABLE" ]]; then
+ chmod +x "$TARGET"
+ else
+ chmod -x "$TARGET"
+ fi
+ }
+ '';
+
+ copyFile = { source, executable, target, ... }: ''
+ copyFile ${escapeShellArgs [
+ source
+ (if executable == null then "inherit" else toString executable)
+ ]}
+ '';
+
+ installFile = writeShellApplication {
+ name = "kobo-install-file";
+ runtimeInputs = [ pkgs.coreutils ];
+ text = ''
+ DRY_RUN_ARG="''${1-}"
+ LOCAL_DIR="''${2-}"
+ KOBO_DIR="''${3-}"
+ LOCAL_FILE="''${4-}"
+
+ FILENAME="''${LOCAL_FILE/#$LOCAL_DIR}"
+ KOBO_FILE="$KOBO_DIR/$FILENAME"
+
+ ${toShellVar "MANIFEST" (cfg.manifestLookupFor "$LOCAL_FILE" "$KOBO_FILE")}
+
+ ACTION="''${MANIFEST["$FILENAME"]}"
+
+ if [[ -n "$ACTION" ]]; then
+ $DRY_RUN_ARG eval "$ACTION"
+ elif [[ -d "$LOCAL_FILE" ]]; then
+ $DRY_RUN_ARG mkdir -p "$KOBO_FILE"
+ else
+ $DRY_RUN_ARG mkdir -p "$(dirname "$KOBO_FILE")"
+ $DRY_RUN_ARG cp -f "$LOCAL_FILE" "$KOBO_FILE"
+ fi
+ '';
+ };
+in {
+ options.build = {
+ allFiles = mkOption {
+ readOnly = true;
+ internal = true;
+ default = with config; concatMap (_: attrValues) [
+ file
+ kfmon.file
+ kobo.file
+ koreader.file
+ nickel.file
+ plato.file
+ ];
+ apply = filter (v: v.enable);
+ };
+
+ allManifests = mkOption {
+ readOnly = true;
+ internal = true;
+ default = with config; concatMap (_: attrValues) [
+ manifest
+ kfmon.manifest
+ kobo.manifest
+ koreader.manifest
+ nickel.manifest
+ plato.manifest
+ ];
+ apply = filter (v: v.enable);
+ };
+
+ manifestLookup = mkOption {
+ readOnly = true;
+ internal = true;
+ type = with types; attrsOf (functionTo (functionTo str));
+ default =
+ let
+ split = concatMap ({ targets, mergeTool, ... }: map (name: { inherit name; value = mergeTool; }) targets);
+ in listToAttrs split;
+ };
+
+ manifestLookupFor = mkOption {
+ readOnly = true;
+ internal = true;
+ type = with types; functionTo (functionTo (attrsOf str));
+ default = x: y: mapAttrs (_: f: f x y) cfg.manifestLookup;
+ };
+
+ src = mkOption {
+ type = types.package;
+ readOnly = true;
+ internal = true;
+ default = pkgs.stdenv.mkDerivation {
+ inherit (config) src;
+ name = "kobo_src";
+ phases = [ "installPhase" ];
+ installPhase = ''
+ mkdir -pv $out
+ cp -rv $src/. $out/
+ chmod -R +w $out
+
+ REALOUT="$(realpath -m "$out")"
+
+ ${copyFileFunc}
+
+ ${concatStringsSep "\n" (
+ mapAttrsToList (_: copyFile) cfg.allFiles
+ )}
+ '';
+ };
+ };
+
+ installer = mkOption {
+ type = types.package;
+ readOnly = true;
+ internal = true;
+ default = pkgs.writeShellApplication {
+ name = "kobo-installer";
+ runtimeInputs = [
+ pkgs.coreutils
+ pkgs.util-linux
+ ];
+ text = '' #TODO DRY_RUN_ARG
+ KOBO_LABEL="''${1:-KOBOeReader}"
+
+ KOBO_MOUNTPOINT="$(findmnt -nlo TARGET LABEL="$KOBO_LABEL")"
+ if [[ -z "$KOBO_MOUNTPOINT" ]]; then
+ echo "Couldn't find a Kobo eReader volume with label $KOBO_LABEL. Are you sure one is actually mounted?"
+ exit 255
+ fi
+
+ KOBO_DIR="$KOBO_MOUNTPOINT/.kobo"
+ if [[ ! -d "$KOBO_DIR" ]]; then
+ echo "It doesn't seem like $KOBO_MOUNTPOINT actually points to a Kobo eReader since it doesn't contain a .kobo directory . . . "
+ exit 255
+ fi
+
+ find "${cfg.src}/" -not -path "${cfg.src}/" -exec ${installFile}/bin/kobo-install-file "" "${cfg.src}" "$KOBO_DIR" {} \;
+ '';
+ };
+ };
+ };
+}
diff --git a/modules/default.nix b/modules/default.nix
index 8e04cce..856ece0 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -1,6 +1,9 @@
{
imports = [
- ./installer.nix
+ # ./installer.nix
+ ./build.nix
+ ./file.nix
+ ./manifest.nix
./kfmon.nix
./kobo.nix
./koreader.nix
diff --git a/modules/file.nix b/modules/file.nix
index a52fb84..7bd2549 100644
--- a/modules/file.nix
+++ b/modules/file.nix
@@ -3,44 +3,5 @@ with builtins // lib;
let
cfg = config.file;
in {
- options.file = mkOption {
- default = {};
- type = with types; lazyAttrsOf (submodule ({ name, config, ... }: {
- options = {
- enable = mkEnableOption name // { default = true; };
- target = mkOption {
- type = types.str;
- default = name;
- };
- executable = mkOption {
- type = with types; nullOr bool;
- default = null;
- };
- directory = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Enable this if the source file is a directory. Note that directories are copied first when forming the source
- '';
- };
- source = mkOption {
- type = types.path;
- };
- text = mkOption {
- type = with types; nullOr lines;
- default = null;
- };
- };
-
- config = mkMerge [
- (mkIf (config.text != null) {
- directory = false;
- source = pkgs.writeText name config.text;
- })
- (mkIf (config.text == "") {
- enable = false;
- })
- ];
- }));
- };
+ options.file = (import ./lib/file.nix { inherit pkgs lib; } "").option;
}
diff --git a/modules/kfmon.nix b/modules/kfmon.nix
index 772a10b..33f6a9c 100644
--- a/modules/kfmon.nix
+++ b/modules/kfmon.nix
@@ -2,6 +2,7 @@
with builtins // lib;
let
cfg = config.kfmon;
+ importOption = p: (import p { inherit pkgs lib; } cfg.path).option;
in {
options.kfmon = {
enable = mkEnableOption "KFMon";
@@ -12,19 +13,13 @@ in {
description = "Relative path to kfmon within src";
};
- file = mkOption {
- type = options.file.type;
- default = {};
- description = "Files relative to ${cfg.path}";
- };
+ file = importOption ./lib/file.nix;
+ manifest = importOption ./lib/manifest.nix;
+ # file = mkOption {
+ # type = options.file.type;
+ # default = {};
+ # description = "Files relative to ${cfg.path}";
+ # };
};
- config = mkIf cfg.enable {
- file = mapAttrs' (n: v: {
- name = "kfmon-${n}";
- value = v // {
- target = "${cfg.path}/${v.target}";
- };
- }) cfg.file
- };
}
diff --git a/modules/kobo.nix b/modules/kobo.nix
index 229a5d1..57f7a88 100644
--- a/modules/kobo.nix
+++ b/modules/kobo.nix
@@ -3,6 +3,7 @@ with builtins // lib;
let
cfg = config.kobo;
ini = pkgs.formats.ini {};
+ importOption = p: (import p { inherit pkgs lib; } cfg.path).option;
in {
options.kobo = {
enable = mkEnableOption "main configurations";
@@ -13,51 +14,30 @@ in {
description = "Relative path to main Kobo config";
};
- file = mkOption {
- type = options.file.type;
- default = {};
- description = "Files relative to ${cfg.path}";
- };
-
- manifest = mkOption {
- type = options.manifest.type;
- default = {};
- description = "Manifest relative to ${cfg.path}";
- };
+ file = importOption ./lib/file.nix;
+ manifest = importOption ./lib/manifest.nix;
config = mkOption {
type = ini.type;
default = {};
description = "https://wiki.mobileread.com/wiki/Kobo_Configuration_Options";
};
-
- # src = mkOption {
- # type = types.package;
- # description = "The base source files to use";
- # default = with pkgs.kobo.src;
- # if config.plato.enable && config.koreader.enable then KOReader-Plato
- # else if config.plato.enable then Plato
- # else if config.koreader.enable then KOReader
- # else if config.kfmon.enable then KFMon
- # else error "At least one of plato, koreader or kfmon must be enabled in order to use a default package";
- # };
-
};
config = {
- file = mapAttrs' (n: v: {
- name = "kobo-${n}";
- value = v // {
- target = "${cfg.path}/${v.target}";
- };
- }) cfg.file;
+ # file = mapAttrs' (n: v: {
+ # name = "kobo-${n}";
+ # value = v // {
+ # target = "${cfg.path}/${v.target}";
+ # };
+ # }) cfg.file;
- manifest = mapAttrs' (n: v: {
- name = "kobo-${n}";
- value = v // {
- targets = map (x: "${cfg.path}/${x}") v.targets;
- };
- }) cfg.manifest;
+ # manifest = mapAttrs' (n: v: {
+ # name = "kobo-${n}";
+ # value = v // {
+ # targets = map (x: "${cfg.path}/${x}") v.targets;
+ # };
+ # }) cfg.manifest;
kobo = {
config = {
@@ -82,4 +62,5 @@ in {
};
- }
+ };
+}
diff --git a/modules/koreader.nix b/modules/koreader.nix
index 0a7300a..aec90fe 100644
--- a/modules/koreader.nix
+++ b/modules/koreader.nix
@@ -2,6 +2,7 @@
with builtins // lib;
let
cfg = config.koreader;
+ importOption = p: (import p { inherit pkgs lib; } cfg.path).option;
in {
options.koreader = {
enable = mkEnableOption "KOReader";
@@ -14,22 +15,25 @@ in {
nickelEntry = mkEnableOption "Launch KOReader directly via nickelMenu";
- file = mkOption {
- type = options.file.type;
- default = {};
- description = "Files relative to ${cfg.path}";
- };
+ file = importOption ./lib/file.nix;
+ manifest = importOption ./lib/manifest.nix;
+
+ # file = mkOption {
+ # type = options.file.type;
+ # default = {};
+ # description = "Files relative to ${cfg.path}";
+ # };
};
config = mkIf cfg.enable {
- file = mapAttrs' (n: v: {
- name = "koreader-${n}";
- value = v // {
- target = "${cfg.path}/${v.target}";
- };
- }) cfg.file
+ # file = mapAttrs' (n: v: {
+ # name = "koreader-${n}";
+ # value = v // {
+ # target = "${cfg.path}/${v.target}";
+ # };
+ # }) cfg.file;
- nickel.menu.items = mkIf cfg.nickelEntry {
+ nickel.menu.item = mkIf cfg.nickelEntry {
koreader = singleton {
location = "main";
label = "KOReader";
diff --git a/modules/lib/file.nix b/modules/lib/file.nix
new file mode 100644
index 0000000..4e7a595
--- /dev/null
+++ b/modules/lib/file.nix
@@ -0,0 +1,43 @@
+{ lib, pkgs, ... }:
+with builtins // lib;
+
+basePath:
+rec {
+ option = mkOption {
+ type = fileType;
+ default = {};
+ description = "Files relative to ${basePath}";
+ };
+
+ type = types.attrsOf (types.submodule ({ name, config, ... }: {
+ options = {
+ enable = mkEnableOption name // { default = text != ""; };
+ target = mkOption {
+ type = types.str;
+ default = name;
+ apply = p: if basePath == "" || isPrefix basePath p then p else "${basePath}/${p}";
+ };
+ executable = mkOption {
+ type = with types; nullOr bool;
+ default = null;
+ };
+ source = mkOption {
+ type = types.path;
+ };
+ text = mkOption {
+ type = with types; nullOr lines;
+ default = null;
+ };
+ };
+
+ config = mkMerge [
+ (mkIf (config.text != null) {
+ source = mkDefault pkgs.writeTextFile {
+ inherit name;
+ inherit (config) text;
+ executable = config.executable == true;
+ };
+ })
+ ];
+ }))
+}
diff --git a/modules/lib/manifest.nix b/modules/lib/manifest.nix
new file mode 100644
index 0000000..1acb567
--- /dev/null
+++ b/modules/lib/manifest.nix
@@ -0,0 +1,41 @@
+{ pkgs, lib, ... }:
+with builtins // lib;
+
+basePath:
+rec {
+ option = mkOption {
+ type = manifestType;
+ default = {};
+ description = "Manifest relative to ${basePath}";
+ };
+ type = types.attrsOf (types.submodule ({ name, config, ... }: {
+ options = {
+ enable = mkEnableOption name // { default = true; };
+ targets = mkOption {
+ type = with types; listOf str;
+ default = [ name ];
+ apply = map (p: if basePath = "" || isPrefix basePath p then p else "${basePath}/${p}");
+ };
+ mergeTool = mkOption {
+ type = with types; functionTo (functionTo str);
+ description = ''
+ Sometimes we don't just want to overwrite the existing kobo file; instead we need to merge them.
+ This is the executable which does this.
+ The first argument is the local file and the second is the kobo file.
+ Note that the local file path and the kobo file path only disagree in their top-level directory and otherwise are the same path.
+ '';
+ example = ''
+ localFile: koboFile: "cp ''${localFile} ''${koboFile}"
+ '';
+ };
+ # remoteOnly = mkOption {
+ # type = types.bool;
+ # default = false;
+ # description = ''
+ # In general, the manifest only considers local files that match the target/pattern.
+ # Setting this to true means that the kobo files will be scanned and the provided mergeTool will be run with the first argument set to null.
+ # '';
+ # };
+ };
+ }))
+}
diff --git a/modules/manifest.nix b/modules/manifest.nix
index 718ffb4..30a2060 100644
--- a/modules/manifest.nix
+++ b/modules/manifest.nix
@@ -25,7 +25,7 @@ in {
'';
};
remoteOnly = mkOption {
- type = types.bool
+ type = types.bool;
default = false;
description = ''
In general, the manifest only considers local files that match the target/pattern.
diff --git a/modules/nickel.nix b/modules/nickel.nix
index 948dbaf..4d22c70 100644
--- a/modules/nickel.nix
+++ b/modules/nickel.nix
@@ -2,6 +2,7 @@
with builtins // lib;
let
cfg = config.nickel;
+ importOption = p: (import p { inherit pkgs lib; } cfg.path).option;
action = mkOption {
type = types.enum [
"cmd_spawn"
@@ -57,11 +58,13 @@ in {
description = "Relative path to nickelMenu within src";
};
- file = mkOption {
- type = options.file.type;
- default = {};
- description = "Files relative to ${cfg.path}";
- };
+ file = importOption ./lib/file.nix;
+ manifest = importOption ./lib/manifest.nix;
+ # file = mkOption {
+ # type = options.file.type;
+ # default = {};
+ # description = "Files relative to ${cfg.path}";
+ # };
menu = {
item = mkOption {
@@ -133,11 +136,11 @@ in {
];
};
- file = mapAttrs' (n: v: {
- name = "nm-${n}";
- value = v // {
- target = "${cfg.path}/${v.target}";
- };
- }) cfg.file
+ # file = mapAttrs' (n: v: {
+ # name = "nm-${n}";
+ # value = v // {
+ # target = "${cfg.path}/${v.target}";
+ # };
+ # }) cfg.file;
};
}
diff --git a/modules/plato.nix b/modules/plato.nix
index f274f00..2fb1016 100644
--- a/modules/plato.nix
+++ b/modules/plato.nix
@@ -3,13 +3,14 @@ with builtins // lib;
let
cfg = config.plato;
toml = pkgs.formats.toml {};
+ importOption = p: (import p { inherit pkgs lib; } cfg.path).option;
in {
imports = [
./nickel.nix
];
options.plato = {
- enable = mkEnableOpiton "Plato";
+ enable = mkEnableOption "Plato";
path = mkOption {
type = types.srt;
@@ -17,17 +18,20 @@ in {
description = "Relative path to Plato within src";
};
- file = mkOption {
- type = options.file.type;
- default = {};
- description = "Files relative to ${cfg.path}";
- };
+ file = importOption ./lib/file.nix;
+ manifest = importOption ./lib/manifest.nix;
- manifest = mkOption {
- type = options.manifest.type;
- default = {};
- description = "Manifest relative to ${cfg.path}";
- };
+ # file = mkOption {
+ # type = options.file.type;
+ # default = {};
+ # description = "Files relative to ${cfg.path}";
+ # };
+
+ # manifest = mkOption {
+ # type = options.manifest.type;
+ # default = {};
+ # description = "Manifest relative to ${cfg.path}";
+ # };
nickelEntry = mkEnableOption "Launch Plato directly from nickelMenu";
@@ -138,7 +142,7 @@ in {
name = if hasSuffix ".css" n1 then n1 else "{n1}.css";
in {
inherit name;
- value = { inherit text; }
+ value = { inherit text; };
}) cfg.css)
(mapAttrs' (n: t:
@@ -153,11 +157,11 @@ in {
{
dictionaries = {
- directory = true;
+ # directory = true;
source = cfg.allDictionaries;
};
fonts = {
- directory = true;
+ # directory = true;
source = cfg.allFonts;
};
}
@@ -169,19 +173,19 @@ in {
};
};
- file = mapAttrs' (n: v: {
- name = "plato-${n}";
- value = v // {
- target = "${cfg.path}/${v.target}";
- };
- }) cfg.file;
-
- manifest = mapAttrs' (n: v: {
- name = "plato-${n}";
- value = v // {
- targets = map (x: "${cfg.path}/${x}") v.targets;
- };
- }) cfg.manifest;
+ # file = mapAttrs' (n: v: {
+ # name = "plato-${n}";
+ # value = v // {
+ # target = "${cfg.path}/${v.target}";
+ # };
+ # }) cfg.file;
+
+ # manifest = mapAttrs' (n: v: {
+ # name = "plato-${n}";
+ # value = v // {
+ # targets = map (x: "${cfg.path}/${x}") v.targets;
+ # };
+ # }) cfg.manifest;
nickel.menu.item = mkIf cfg.nickelEntry {
plato = singleton {
diff --git a/modules/root.nix b/modules/root.nix
new file mode 100644
index 0000000..d74fe66
--- /dev/null
+++ b/modules/root.nix
@@ -0,0 +1,21 @@
+{ config, pkgs, lib, ... }:
+with builtins // lib;
+let
+ importOption = p: (import p { inherit pkgs lib; } "").option;
+in {
+ options = {
+ file = importOption ./lib/file.nix;
+ manifest = importOption ./lib/manifest.nix;
+
+ src = mkOption {
+ type = types.package;
+ description = "The base source files to use";
+ default = with pkgs.kobo.src;
+ if config.plato.enable && config.koreader.enable then KOReader-Plato
+ else if config.plato.enable then Plato
+ else if config.koreader.enable then KOReader
+ else if config.kfmon.enable then KFMon
+ else pkgs.runCommandLocal "empty-kobo" {} "mkdir -p $out";
+ };
+ };
+}