nix: implement flake

This commit introduces the ability to install Docspell from a Nix flake.
There are no major changes to the logic of the previous modules outside of
organizing them in a flake and adding a simple check script.
This commit is contained in:
Vladimir Timofeenko 2022-11-28 13:45:34 -08:00
parent 1d39b5c74e
commit ae8bd1d85b
13 changed files with 360 additions and 511 deletions

View File

@ -1,10 +0,0 @@
#!/usr/bin/env bash
if [ "$1" = "-f" ]; then
echo "Deleting current state image..."
rm *.qcow2
fi
nixos-rebuild build-vm \
-I nixos-config=./configuration-test.nix \
-I nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-21.11.tar.gz

View File

@ -1,6 +1,5 @@
{ config, pkgs, ... }:
let
docspell = import ./release.nix;
full-text-search = {
enabled = true;
solr.url = "http://localhost:${toString config.services.solr.port}/solr/docspell";
@ -12,7 +11,6 @@ let
};
in
{
imports = docspell.modules ++ [ ./solr.nix ];
i18n = {
defaultLocale = "en_US.UTF-8";
@ -23,17 +21,6 @@ in
password = "root";
};
nixpkgs = {
config = {
packageOverrides = pkgs:
let
callPackage = pkgs.lib.callPackageWith(custom // pkgs);
custom = {
docspell = callPackage docspell.currentPkg {};
};
in custom;
};
};
services.docspell-joex = {
enable = true;
@ -57,7 +44,8 @@ in
};
};
openid = [
{ enabled = true;
{
enabled = true;
display = "Local";
provider = {
provider-id = "local";
@ -73,10 +61,9 @@ in
};
environment.systemPackages =
[ pkgs.docspell.server
pkgs.docspell.joex
[
pkgs.jq
pkgs.telnet
pkgs.inetutils
pkgs.htop
pkgs.openjdk
];
@ -88,9 +75,9 @@ in
networking = {
hostName = "docspelltest";
firewall.allowedTCPPorts = [7880];
firewall.allowedTCPPorts = [ 7880 ];
};
system.stateVersion = "21.05";
system.stateVersion = "22.05";
}

7
nix/checks/default.nix Normal file
View File

@ -0,0 +1,7 @@
{ ... }:
{
imports = [
./configuration-test.nix
./solr.nix
];
}

View File

@ -1,8 +1,15 @@
{ config, pkgs, ... }:
{ config, pkgs, lib, ... }:
# This module sets up solr with one core. It is a bit tedious…. If you
# know a better solution, please let me know.
{
nixpkgs.config = {
permittedInsecurePackages = [
"solr-8.6.3"
# NOTE: Qtwebkit is a dep for wkhtmltopdf, this line is needed until #201765 is fixed in nixpkgs
"qtwebkit-5.212.0-alpha4"
];
};
services.solr = {
enable = true;
@ -15,7 +22,7 @@
solrPort = toString config.services.solr.port;
initSolr = ''
if [ ! -f ${config.services.solr.stateDir}/docspell_core ]; then
while ! echo "" | ${pkgs.telnet}/bin/telnet localhost ${solrPort}
while ! echo "" | ${pkgs.inetutils}/bin/telnet localhost ${solrPort}
do
echo "Waiting for SOLR become ready..."
sleep 1.5
@ -25,11 +32,12 @@
fi
'';
in
{ script = initSolr;
after = [ "solr.target" ];
wantedBy = [ "multi-user.target" ];
requires = [ "solr.target" ];
description = "Create a core at solr";
};
{
script = initSolr;
after = [ "solr.target" ];
wantedBy = [ "multi-user.target" ];
requires = [ "solr.target" ];
description = "Create a core at solr";
};
}

3
nix/checks/testScript.py Normal file
View File

@ -0,0 +1,3 @@
with subtest("services are up"):
machine.wait_for_unit("docspell-restserver")
machine.wait_for_unit("docspell-joex")

26
nix/flake.lock generated Normal file
View File

@ -0,0 +1,26 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1669735802,
"narHash": "sha256-qtG/o/i5ZWZLmXw108N2aPiVsxOcidpHJYNkT45ry9Q=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "731cc710aeebecbf45a258e977e8b68350549522",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-22.11",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

119
nix/flake.nix Normal file
View File

@ -0,0 +1,119 @@
{
description = "Docspell flake";
inputs = {
nixpkgs.url = "nixpkgs/nixos-22.11";
};
outputs = { self, nixpkgs }:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" ];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
# Version config
cfg = {
v0_39_0 = rec {
version = "0.39.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "sha256-YZzYOqJzp2J5ioTT8H7qpRA3mHDRjJYNA7fUOEQWSfY=";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "sha256-6Vcuk9+JDkNAdTQd+sRLARfE+y9cbtGE8hWTTcxZk3E=";
};
};
};
current_version = cfg.v0_39_0;
inherit (current_version) version;
in
rec
{
overlays.default = final: prev: {
docspell-server = with final; stdenv.mkDerivation {
inherit version;
pname = "docspell-server";
src = fetchzip current_version.server;
buildInputs = [ jdk11 ];
buildPhase = "true";
installPhase = ''
mkdir -p $out/{bin,docspell-restserver-${version}}
cp -R * $out/docspell-restserver-${version}/
cat > $out/bin/docspell-restserver <<-EOF
#!${bash}/bin/bash
$out/docspell-restserver-${version}/bin/docspell-restserver -java-home ${jdk11} "\$@"
EOF
chmod 755 $out/bin/docspell-restserver
'';
};
docspell-joex = with final; stdenv.mkDerivation rec {
inherit version;
pname = "docspell-joex";
src = fetchzip current_version.joex;
buildInputs = [ jdk11 ];
buildPhase = "true";
installPhase = ''
mkdir -p $out/{bin,docspell-joex-${version}}
cp -R * $out/docspell-joex-${version}/
cat > $out/bin/docspell-joex <<-EOF
#!${bash}/bin/bash
$out/docspell-joex-${version}/bin/docspell-joex -java-home ${jdk11} "\$@"
EOF
chmod 755 $out/bin/docspell-joex
'';
};
};
packages = forAllSystems (system:
{
default = (import nixpkgs {
inherit system;
overlays = [ self.overlays.default ];
}).docspell-server;
});
checks = forAllSystems
(system: {
build = self.packages.${system}.default;
test =
with import (nixpkgs + "/nixos/lib/testing-python.nix")
{
inherit system;
};
makeTest {
name = "docspell";
nodes = {
machine = { ... }: {
imports = [
self.nixosModules.default
./checks
];
};
};
testScript = builtins.readFile ./checks/testScript.py;
};
});
nixosModules = {
default = { ... }: {
imports = [
((import ./modules/server.nix) self.overlays.default)
((import ./modules/joex.nix) self.overlays.default)
];
};
server = ((import ./modules/server.nix) self.overlays.default);
joex = ((import ./modules/joex.nix) self.overlays.default);
};
};
}

View File

@ -1,13 +1,13 @@
{config, lib, pkgs, ...}:
overlay: { config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.docspell-joex;
user = if cfg.runAs == null then "docspell" else cfg.runAs;
configFile = pkgs.writeText "docspell-joex.conf" ''
{"docspell": { "joex":
${builtins.toJSON cfg}
}}
{"docspell": { "joex":
${builtins.toJSON cfg}
}}
'';
defaults = {
app-id = "joex1";
@ -83,20 +83,20 @@ let
schedule = "Sun *-*-* 00:00:00 UTC";
sender-account = "";
smtp-id = "";
recipients = [];
recipients = [ ];
subject = "Docspell {{ latestVersion }} is available";
body = ''
Hello,
Hello,
You are currently running Docspell {{ currentVersion }}. Version *{{ latestVersion }}*
is now available, which was released on {{ releasedAt }}. Check the release page at:
You are currently running Docspell {{ currentVersion }}. Version *{{ latestVersion }}*
is now available, which was released on {{ releasedAt }}. Check the release page at:
<https://github.com/eikek/docspell/releases/latest>
<https://github.com/eikek/docspell/releases/latest>
Have a nice day!
Have a nice day!
Docpell Update Check
'';
Docpell Update Check
'';
};
extraction = {
pdf = {
@ -110,7 +110,7 @@ Docpell Update Check
page-range = {
begin = 10;
};
ghostscript = {
ghostscript = {
working-dir = "/tmp/docspell-extraction";
command = {
program = "${pkgs.ghostscript}/bin/gs";
@ -126,9 +126,9 @@ Docpell Update Check
};
};
tesseract = {
command= {
command = {
program = "${pkgs.tesseract4}/bin/tesseract";
args = ["{{file}}" "stdout" "-l" "{{lang}}" ];
args = [ "{{file}}" "stdout" "-l" "{{lang}}" ];
timeout = "5 minutes";
};
};
@ -149,7 +149,8 @@ Docpell Update Check
enabled = true;
item-count = 600;
classifiers = [
{ "useSplitWords" = "true";
{
"useSplitWords" = "true";
"splitWordsTokenizerRegexp" = ''[\p{L}][\p{L}0-9]*|(?:\$ ?)?[0-9]+(?:\.[0-9]{2})?%?|\s+|.'';
"splitWordsIgnoreRegexp" = ''\s+'';
"useSplitPrefixSuffixNGrams" = "true";
@ -169,14 +170,14 @@ Docpell Update Check
markdown = {
internal-css = ''
body { padding: 2em 5em; }
'';
body { padding: 2em 5em; }
'';
};
wkhtmlpdf = {
command = {
program = "${pkgs.wkhtmltopdf}/bin/wkhtmltopdf";
args = ["-s" "A4" "--encoding" "UTF-8" "-" "{{outfile}}"];
args = [ "-s" "A4" "--encoding" "UTF-8" "-" "{{outfile}}" ];
timeout = "2 minutes";
};
working-dir = "/tmp/docspell-convert";
@ -185,7 +186,7 @@ Docpell Update Check
tesseract = {
command = {
program = "${pkgs.tesseract4}/bin/tesseract";
args = ["{{infile}}" "out" "-l" "{{lang}}" "pdf" "txt"];
args = [ "{{infile}}" "out" "-l" "{{lang}}" "pdf" "txt" ];
timeout = "5 minutes";
};
working-dir = "/tmp/docspell-convert";
@ -194,7 +195,7 @@ Docpell Update Check
unoconv = {
command = {
program = "${pkgs.unoconv}/bin/unoconv";
args = ["-f" "pdf" "-o" "{{outfile}}" "{{infile}}"];
args = [ "-f" "pdf" "-o" "{{outfile}}" "{{infile}}" ];
timeout = "2 minutes";
};
working-dir = "/tmp/docspell-convert";
@ -205,12 +206,14 @@ Docpell Update Check
command = {
program = "${pkgs.ocrmypdf}/bin/ocrmypdf";
args = [
"-l" "{{lang}}"
"--skip-text"
"--deskew"
"-j" "1"
"{{infile}}"
"{{outfile}}"
"-l"
"{{lang}}"
"--skip-text"
"--deskew"
"-j"
"1"
"{{infile}}"
"{{outfile}}"
];
timeout = "5 minutes";
};
@ -219,7 +222,7 @@ Docpell Update Check
};
files = {
chunk-size = 524288;
valid-mime-types = [];
valid-mime-types = [ ];
};
full-text-search = {
enabled = false;
@ -238,7 +241,7 @@ Docpell Update Check
user = "pguser";
password = "";
};
pg-config = {};
pg-config = { };
pg-query-parser = "websearch_to_tsquery";
pg-rank-normalization = [ 4 ];
};
@ -260,7 +263,7 @@ Docpell Update Check
fail-fast = true;
run-timeout = "15 minutes";
nix-runner = {
nix-binary = "${pkgs.nixFlakes}/bin/nix";
nix-binary = "${pkgs.nix}/bin/nix";
build-timeout = "15 minutes";
};
docker-runner = {
@ -270,7 +273,8 @@ Docpell Update Check
};
};
};
in {
in
{
## interface
options = {
@ -299,7 +303,7 @@ in {
};
jvmArgs = mkOption {
type = types.listOf types.str;
default = [];
default = [ ];
example = [ "-J-Xmx1G" ];
description = "The options passed to the executable for setting jvm arguments.";
};
@ -318,7 +322,7 @@ in {
};
bind = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
address = mkOption {
type = types.str;
@ -337,7 +341,7 @@ in {
};
logging = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
minimum-level = mkOption {
type = types.str;
@ -364,10 +368,10 @@ in {
type = types.bool;
default = defaults.mail-debug;
description = ''
Enable or disable debugging for e-mail related functionality. This
applies to both sending and receiving mails. For security reasons
logging is not very extensive on authentication failures. Setting
this to true, results in a lot of data printed to stdout.
Enable or disable debugging for e-mail related functionality. This
applies to both sending and receiving mails. For security reasons
logging is not very extensive on authentication failures. Setting
this to true, results in a lot of data printed to stdout.
'';
};
@ -405,7 +409,7 @@ in {
};
send-mail = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
list-id = mkOption {
type = types.str;
@ -429,7 +433,7 @@ in {
};
scheduler = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
pool-size = mkOption {
type = types.int;
@ -485,7 +489,7 @@ in {
};
periodic-scheduler = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
wakeup-period = mkOption {
type = types.str;
@ -506,10 +510,10 @@ in {
};
user-tasks = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
scan-mailbox = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
max-folders = mkOption {
type = types.int;
@ -534,12 +538,12 @@ in {
type = types.int;
default = defaults.user-tasks.scan-mailbox.max-mails;
description = ''
A limit on how many mails to process in one job run. This is
meant to avoid too heavy resource allocation to one
user/collective.
A limit on how many mails to process in one job run. This is
meant to avoid too heavy resource allocation to one
user/collective.
If more than this number of mails is encountered, a warning is
logged.
If more than this number of mails is encountered, a warning is
logged.
'';
};
};
@ -554,7 +558,7 @@ in {
};
house-keeping = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
schedule = mkOption {
type = types.str;
@ -565,7 +569,7 @@ in {
'';
};
cleanup-invites = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -587,7 +591,7 @@ in {
'';
};
cleanup-jobs = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -622,7 +626,7 @@ in {
'';
};
cleanup-remember-me = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -641,7 +645,7 @@ in {
};
cleanup-downloads = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -660,7 +664,7 @@ in {
};
check-nodes = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -687,7 +691,7 @@ in {
};
update-check = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -769,10 +773,10 @@ in {
};
extraction = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
pdf = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
min-text-len = mkOption {
type = types.int;
@ -791,7 +795,7 @@ in {
description = "Settings for PDF extraction";
};
preview = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
dpi = mkOption {
type = types.int;
@ -813,7 +817,7 @@ in {
description = "";
};
ocr = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
max-image-size = mkOption {
type = types.int;
@ -824,7 +828,7 @@ in {
'';
};
page-range = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
begin = mkOption {
type = types.int;
@ -849,7 +853,7 @@ in {
'';
};
ghostscript = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
working-dir = mkOption {
type = types.str;
@ -857,7 +861,7 @@ in {
description = "Directory where the extraction processes can put their temp files";
};
command = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
program = mkOption {
type = types.str;
@ -885,10 +889,10 @@ in {
description = "The ghostscript command.";
};
unpaper = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
command = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
program = mkOption {
type = types.str;
@ -916,10 +920,10 @@ in {
description = "The unpaper command.";
};
tesseract = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
command = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
program = mkOption {
type = types.str;
@ -968,7 +972,7 @@ in {
};
text-analysis = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
max-length = mkOption {
type = types.int;
@ -993,7 +997,7 @@ in {
};
nlp = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
mode = mkOption {
type = types.str;
@ -1051,7 +1055,7 @@ in {
};
regex-ner = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
max-entries = mkOption {
type = types.int;
@ -1093,7 +1097,7 @@ in {
};
classification = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -1151,7 +1155,7 @@ in {
};
convert = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
chunk-size = mkOption {
type = types.int;
@ -1180,7 +1184,7 @@ in {
'';
};
markdown = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
internal-css = mkOption {
type = types.str;
@ -1202,7 +1206,7 @@ in {
'';
};
wkhtmlpdf = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
working-dir = mkOption {
type = types.str;
@ -1210,7 +1214,7 @@ in {
description = "Directory where the conversion processes can put their temp files";
};
command = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
program = mkOption {
type = types.str;
@ -1241,7 +1245,7 @@ in {
'';
};
tesseract = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
working-dir = mkOption {
type = types.str;
@ -1249,7 +1253,7 @@ in {
description = "Directory where the conversion processes can put their temp files";
};
command = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
program = mkOption {
type = types.str;
@ -1280,7 +1284,7 @@ in {
'';
};
unoconv = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
working-dir = mkOption {
type = types.str;
@ -1288,7 +1292,7 @@ in {
description = "Directory where the conversion processes can put their temp files";
};
command = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
program = mkOption {
type = types.str;
@ -1326,7 +1330,7 @@ in {
};
ocrmypdf = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -1339,7 +1343,7 @@ in {
description = "Directory where the conversion processes can put their temp files";
};
command = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
program = mkOption {
type = types.str;
@ -1396,7 +1400,7 @@ in {
'';
};
files = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
chunk-size = mkOption {
type = types.int;
@ -1425,10 +1429,10 @@ in {
};
});
default = defaults.files;
description= "Settings for how files are stored.";
description = "Settings for how files are stored.";
};
full-text-search = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -1448,7 +1452,7 @@ in {
};
solr = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
url = mkOption {
type = types.str;
@ -1486,7 +1490,7 @@ in {
};
postgresql = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
use-default-connection = mkOption {
type = types.bool;
@ -1540,7 +1544,7 @@ in {
};
migration = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
index-all-chunk = mkOption {
type = types.int;
@ -1562,7 +1566,7 @@ in {
description = "Configuration for full-text search.";
};
addons = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
working-dir = mkOption {
type = types.str;
@ -1575,7 +1579,7 @@ in {
description = "Cache directory";
};
executor-config = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
runner = mkOption {
type = types.str;
@ -1593,7 +1597,7 @@ in {
description = "";
};
nspawn = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -1621,7 +1625,7 @@ in {
description = "";
};
nix-runner = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
nix-binary = mkOption {
type = types.str;
@ -1639,7 +1643,7 @@ in {
description = "";
};
docker-runner = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
docker-binary = mkOption {
type = types.str;
@ -1672,6 +1676,8 @@ in {
## implementation
config = mkIf config.services.docspell-joex.enable {
nixpkgs.overlays = [ overlay ];
users.users."${user}" = mkIf (cfg.runAs == null) {
name = user;
isSystemUser = true;
@ -1680,44 +1686,43 @@ in {
description = "Docspell user";
group = user;
};
users.groups."${user}" = mkIf (cfg.runAs == null) {
};
users.groups."${user}" = mkIf (cfg.runAs == null) { };
# Setting up a unoconv listener to improve conversion performance
systemd.services.unoconv =
let
cmd = "${pkgs.unoconv}/bin/unoconv --listener -v";
in
{
description = "Unoconv Listener";
after = [ "networking.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Restart = "always";
};
script =
"${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${user} -c \"${cmd}\"";
{
description = "Unoconv Listener";
after = [ "networking.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Restart = "always";
};
script =
"${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${user} -c \"${cmd}\"";
};
systemd.services.docspell-joex =
let
args = builtins.concatStringsSep " " cfg.jvmArgs;
cmd = "${pkgs.docspell.joex}/bin/docspell-joex ${args} -- ${configFile}";
cmd = "${pkgs.docspell-joex}/bin/docspell-joex ${args} -- ${configFile}";
waitTarget =
if cfg.waitForTarget != null
then
[ cfg.waitForTarget ]
else
[];
[ ];
in
{
description = "Docspell Joex";
after = ([ "networking.target" ] ++ waitTarget);
wantedBy = [ "multi-user.target" ];
path = [ pkgs.gawk ];
{
description = "Docspell Joex";
after = ([ "networking.target" ] ++ waitTarget);
wantedBy = [ "multi-user.target" ];
path = [ pkgs.gawk ];
script =
"${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${user} -c \"${cmd}\"";
};
script =
"${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${user} -c \"${cmd}\"";
};
};
}

View File

@ -1,4 +1,4 @@
{config, lib, pkgs, ...}:
overlay: { config, lib, pkgs, ... }:
with lib;
let
@ -76,7 +76,7 @@ let
user = "pguser";
password = "";
};
pg-config = {};
pg-config = { };
pg-query-parser = "websearch_to_tsquery";
pg-rank-normalization = [ 4 ];
};
@ -124,17 +124,18 @@ let
};
files = {
chunk-size = 524288;
valid-mime-types = [];
valid-mime-types = [ ];
};
addons = {
enabled = false;
allow-impure = true;
allowed-urls = ["*"];
denied-urls = [];
allowed-urls = [ "*" ];
denied-urls = [ ];
};
};
};
in {
in
{
## interface
options = {
@ -153,7 +154,7 @@ in {
};
jvmArgs = mkOption {
type = types.listOf types.str;
default = [];
default = [ ];
example = [ "-J-Xmx1G" ];
description = "The options passed to the executable for setting jvm arguments.";
};
@ -229,7 +230,7 @@ in {
};
bind = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
address = mkOption {
type = types.str;
@ -248,7 +249,7 @@ in {
};
server-options = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enable-http-2 = mkOption {
type = types.bool;
@ -272,7 +273,7 @@ in {
};
logging = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
minimum-level = mkOption {
type = types.str;
@ -296,7 +297,7 @@ in {
};
auth = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
server-secret = mkOption {
type = types.str;
@ -317,7 +318,7 @@ in {
'';
};
remember-me = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -341,7 +342,7 @@ in {
};
download-all = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
max-files = mkOption {
type = types.int;
@ -439,12 +440,12 @@ in {
};
};
});
default = [];
default = [ ];
description = "A list of OIDC provider configurations.";
};
integration-endpoint = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -464,7 +465,7 @@ in {
'';
};
allowed-ips = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -488,7 +489,7 @@ in {
'';
};
http-basic = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -518,7 +519,7 @@ in {
'';
};
http-header = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -563,7 +564,7 @@ in {
};
admin-endpoint = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
secret = mkOption {
type = types.str;
@ -577,7 +578,7 @@ in {
};
full-text-search = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -594,7 +595,7 @@ in {
description = "The backend to use, either solr or postgresql";
};
solr = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
url = mkOption {
type = types.str;
@ -632,7 +633,7 @@ in {
};
postgresql = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
use-default-connection = mkOption {
type = types.bool;
@ -691,16 +692,16 @@ in {
};
backend = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
mail-debug = mkOption {
type = types.bool;
default = defaults.backend.mail-debug;
description = ''
Enable or disable debugging for e-mail related functionality. This
applies to both sending and receiving mails. For security reasons
logging is not very extensive on authentication failures. Setting
this to true, results in a lot of data printed to stdout.
Enable or disable debugging for e-mail related functionality. This
applies to both sending and receiving mails. For security reasons
logging is not very extensive on authentication failures. Setting
this to true, results in a lot of data printed to stdout.
'';
};
jdbc = mkOption {
@ -774,7 +775,7 @@ in {
description = "Registration settings";
};
files = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
chunk-size = mkOption {
type = types.int;
@ -803,10 +804,10 @@ in {
};
});
default = defaults.backend.files;
description= "Settings for how files are stored.";
description = "Settings for how files are stored.";
};
addons = mkOption {
type = types.submodule({
type = types.submodule ({
options = {
enabled = mkOption {
type = types.bool;
@ -844,6 +845,7 @@ in {
## implementation
config = mkIf config.services.docspell-restserver.enable {
nixpkgs.overlays = [ overlay ];
users.users."${user}" = mkIf (cfg.runAs == null) {
name = user;
isSystemUser = true;
@ -852,25 +854,24 @@ in {
description = "Docspell user";
group = user;
};
users.groups."${user}" = mkIf (cfg.runAs == null) {
};
users.groups."${user}" = mkIf (cfg.runAs == null) { };
systemd.services.docspell-restserver =
let
args = builtins.concatStringsSep " " cfg.jvmArgs;
cmd = "${pkgs.docspell.server}/bin/docspell-restserver ${args} -- ${configFile}";
in
{
description = "Docspell Rest Server";
after = [ "networking.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.gawk ];
preStart = ''
let
args = builtins.concatStringsSep " " cfg.jvmArgs;
cmd = "${pkgs.docspell-server}/bin/docspell-restserver ${args} -- ${configFile}";
in
{
description = "Docspell Rest Server";
after = [ "networking.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.gawk ];
preStart = ''
'';
script =
"${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${user} -c \"${cmd}\"";
};
script =
"${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${user} -c \"${cmd}\"";
};
};
}

View File

@ -1,54 +0,0 @@
cfg: {stdenv, lib, fetchzip, file, curl, inotifyTools, fetchurl, jdk11, bash, jq, sqlite}:
let
meta = with lib; {
description = "Docspell helps to organize and archive your paper documents.";
homepage = https://github.com/eikek/docspell;
license = licenses.gpl3;
maintainers = [ maintainers.eikek ];
};
in
{ server = stdenv.mkDerivation rec {
name = "docspell-server-${cfg.version}";
src = fetchzip cfg.server;
buildInputs = [ jdk11 ];
buildPhase = "true";
installPhase = ''
mkdir -p $out/{bin,docspell-restserver-${cfg.version}}
cp -R * $out/docspell-restserver-${cfg.version}/
cat > $out/bin/docspell-restserver <<-EOF
#!${bash}/bin/bash
$out/docspell-restserver-${cfg.version}/bin/docspell-restserver -java-home ${jdk11} "\$@"
EOF
chmod 755 $out/bin/docspell-restserver
'';
inherit meta;
};
joex = stdenv.mkDerivation rec {
name = "docspell-joex-${cfg.version}";
src = fetchzip cfg.joex;
buildInputs = [ jdk11 ];
buildPhase = "true";
installPhase = ''
mkdir -p $out/{bin,docspell-joex-${cfg.version}}
cp -R * $out/docspell-joex-${cfg.version}/
cat > $out/bin/docspell-joex <<-EOF
#!${bash}/bin/bash
$out/docspell-joex-${cfg.version}/bin/docspell-joex -java-home ${jdk11} "\$@"
EOF
chmod 755 $out/bin/docspell-joex
'';
inherit meta;
};
}

View File

@ -1,140 +0,0 @@
rec {
cfg = {
v0_39_0 = rec {
version = "0.39.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "sha256-YZzYOqJzp2J5ioTT8H7qpRA3mHDRjJYNA7fUOEQWSfY=";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "sha256-6Vcuk9+JDkNAdTQd+sRLARfE+y9cbtGE8hWTTcxZk3E=";
};
};
v0_38_0 = rec {
version = "0.38.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "sha256-KufKnkg+YXIktWRQ/pUrXVKLLBOb1i/G3u60Y3GwMAw=";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "sha256-Z85SfJfuCZZ24B5TJM0Mpx8NefaLdQpWs7ftkVCiohM=";
};
};
v0_37_0 = rec {
version = "0.37.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "sha256-Emi4lynYsNIZh2B0c6l1LexxDgrnax2Uy19VoPW1Exo=";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "sha256-fWYBTphEtkFCdKun4U7fEQkTLnum/qtLBJs8Y9AqD54=";
};
};
v0_36_0 = rec {
version = "0.36.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "sha256-0qDsvEN5ohv/xvkHywonfMtf3p871VdegJqrg7DaAak=";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "sha256-ovNSdjEKY1oaQruTQN23sGK4lHuBoYgTLVocVNYIt9Y=";
};
};
v0_35_0 = rec {
version = "0.35.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "sha256-WnZME2qyxwWZmArH0TDSZLmxZgM/mQCvgeYOFtsIZNs=";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "sha256-hBBXthKeS8petmRscSr9kUOphkipxvltHkfg7yvN/Ok=";
};
};
v0_34_0 = rec {
version = "0.34.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "0gri5g6mhz8ghqbpzg191mxjacia7dz36j9y90ndns32pzx2w7z3";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "0i485q762afajim3iq4ax9a3snih041s9fvrzh9i68ixk1qrvwz4";
};
};
v0_33_0 = rec {
version = "0.33.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "1nnf5iwycyq8ddc2b0fks5xjqrj921d50b9lw488zs5j387sjmm1";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "07ip74awhilyxyksrq6qb6jbiiiqfxlw5in461n93aggpa5r6ccy";
};
};
v0_32_0 = rec {
version = "0.32.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "0095i9p7ikx8a64137iq95ilj8aiz8rzwxvqz8qkv2ia15g8q65p";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "0k0bvzvdksw2bd33cfdpxw229rpx4g4xnm5qkk2pga35g7k5kgf7";
};
};
v0_31_0 = rec {
version = "0.31.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "17qkq71lqf5yh6p23rhjliwqrid70c6x5iq20msliqzghv6zjn97";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "0ani309kcrn7rslr7qnx9n2z09ba2v8dwnzjkabj9d2kd05mkz7r";
};
};
v0_22_0 = rec {
version = "0.22.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "1lysbqc62c2ijqg948wh882b6609mhal9n4ab9y4xjs788lfvd7h";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "0g5ajkrsnbdig0hw5nz1g75ghvds6f2389zy2ccs4zfjws6xp1nr";
};
tools = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-tools-${version}.zip";
sha256 = "00n9z2z06hr431xascpxmb6vn5lc2a3hz4p2ap3zc1nbkkdwmkh2";
};
};
v0_1_0 = rec {
version = "0.1.0";
server = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-restserver-${version}.zip";
sha256 = "19bmvrk07s4gsw4dszbilfv7jns7bp20lfr0ia73xdmn5w8kdhq0";
};
joex = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-joex-${version}.zip";
sha256 = "175yz0lxra0qv63xjl90hh32idm13c1k1aah2hqc0ncpx22scp5v";
};
tools = {
url = "https://github.com/eikek/docspell/releases/download/v${version}/docspell-tools-${version}.zip";
sha256 = "03w5cxylk2yfkah15qrx5cl21gfly0vwa0czglb1swsri3808rdb";
};
};
};
pkg = v: import ./pkg.nix v;
currentPkg = pkg cfg.v0_39_0;
module-joex = ./module-joex.nix;
module-restserver = ./module-server.nix;
modules = [ module-joex
module-restserver
];
}

View File

@ -10,59 +10,7 @@ weight = 24
Docspell can be installed via the [nix](https://nixos.org/nix) package
manager, which is available for Linux and OSX. Docspell is currently not
part of the [nixpkgs collection](https://nixos.org/nixpkgs/), but you
can use the derivation from this repository. This is sometimes
referred to as [import from
derivation](https://nixos.wiki/wiki/Import_From_Derivation).
For example, the `builtins.fetchTarball` function can be used to
retrieve the files; then import the `release.nix` file:
``` nix
let
docspellsrc = builtins.fetchTarball "https://github.com/eikek/docspell/archive/master.tar.gz";
in
import "${docspellsrc}/nix/release.nix";
```
This creates a set containing a function for creating a derivation for
docspell. This then needs to be called like other custom packages. For
example, in your `~/.nixpkgs/config.nix` you could write this:
``` nix
let
docspellsrc = builtins.fetchTarball "https://github.com/eikek/docspell/archive/master.tar.gz";
docspell = import "${docspellsrc}/nix/release.nix";
in
{ packageOverrides = pkgs:
let
callPackage = pkgs.lib.callPackageWith(custom // pkgs);
custom = {
docspell = callPackage docspell.currentPkg {};
};
in custom;
}
```
The `docspell` custom package is again a set that contains derivations
for all 3 installable docspell programs: the restserver, joex and the
tools.
Then you can install docspell via `nix-shell` or `nix-env`, for example:
``` bash
$ nix-env -iA nixpkgs.docspell.server nixpkgs.docspell.joex nixpkgs.docspell.tools
```
You may need to replace `nixpkgs` with `nixos` when you're on NixOS.
The expression `docspell.currentPkg` refers to the most current
release of Docspell. So even if you use the tarball of the current
master branch, the `release.nix` file only contains derivations for
releases. The expression `docspell.currentPkg` is a shortcut for
selecting the most current release. For example it translates to
`docspell.pkg docspell.cfg.v{{ pversion() }}` if the current version
is `{{version()}}`.
can use the flake from this repository.
## Upgrading
@ -71,9 +19,6 @@ it is recommended to backup your database before upgrading. Should
something not work as expected, restore the database backup and go
back to the previous version.
When using the provided nix setup, the `currentPkg` always points to
the latest release. Thus it is enough to run `nix-build`.
# Docspell on NixOS {#nixos}
If you are running [NixOS](https://nixos.org), there is a module
@ -83,59 +28,22 @@ There are the following modules provided:
- restserver
- joex
- consumedir
The `consumedir` module defines a systemd unit that starts the `dsc
watch` command to watch one or more directories for new files.
You need to import the `release.nix` file as described above in your
`configuration.nix` and then append the docspell module to your list of
modules. Here is an example:
```nix
{ config, pkgs, ... }:
let
docspellsrc = builtins.fetchTarball "https://github.com/eikek/docspell/archive/master.tar.gz";
docspell = import "${docspellsrc}/nix/release.nix";
in
{
imports = [ mymodule1 mymodule2 ] ++ docspell.modules;
# flake.nix
inputs.docspell.url = "github:eikek/docspell?dir=nix/";
nixpkgs = {
config = {
packageOverrides = pkgs:
let
callPackage = pkgs.lib.callPackageWith(custom // pkgs);
custom = {
docspell = callPackage docspell.currentPkg {};
};
in custom;
};
};
services.docspell-restserver = {
enable = true;
base-url = "http://docspelltest:7880";
# ... more settings here
};
services.docspell-joex = {
enable = true;
base-url = "http://docspelltexst:7878";
# ... more settings here
};
services.docspell-consumedir = {
enable = true;
watchDirs = ["/tmp/test"];
source-id = "the-source-id";
};
...
}
# in modules
imports = [
docspell.nixosModules.default
]
services.docspell-joex = { ... }
services.docspell-restserver = { ... }
```
Please see the `nix/module-server.nix` and `nix/module-joex.nix` files
for the set of options. The nixos options are modelled after the
Please see the `nix/modules/server.nix` and `nix/modules/joex.nix` files
for the set of options. The nixos options are modeled after the
default configuration file.
The modules files are only applicable to the newest version of
@ -149,25 +57,13 @@ postgres database. This snippet can be used to create a vm (using
`nixos-rebuild build-vm` as shown above) or a container, for example.
``` nix
{ config, pkgs, ... }:
let
docspellsrc = builtins.fetchTarball "https://github.com/eikek/docspell/archive/master.tar.gz";
docspell = import "${docspellsrc}/nix/release.nix";
in
{
imports = docspell.modules;
# flake.nix
inputs.docspell.url = "github:eikek/docspell?dir=nix/";
nixpkgs = {
config = {
packageOverrides = pkgs:
let
callPackage = pkgs.lib.callPackageWith(custom // pkgs);
custom = {
docspell = callPackage docspell.currentPkg {};
};
in custom;
};
};
# module.nix
{ config, pkgs, docspell, ... }:
{
imports = docspell.nixosModules.default;
##### just for the example…
users.users.root = {

View File

@ -21,8 +21,9 @@ To get started, here are some quick links:
from the [release
page](https://github.com/eikek/docspell/releases/latest).
- via the [nix package manager](@/docs/install/nix.md) and/or as a
[NixOS module](@/docs/install/nix.md#nixos). If you use nix/nixos,
you know what to do. The linked page contains some examples.
[NixOS module](@/docs/install/nix.md#nixos) through a flake.
If you use nix/nixos, you know what to do. The linked page contains
some examples.
- [Unraid](https://www.unraid.net/): There are user provided [notes
and unraid
templates](https://github.com/vakilando/unraid-docker-templates)