diff --git a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
index 1e8a935f8f74..0026b362caf0 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
@@ -373,6 +373,14 @@
services.multipath.
+
+
+ seafile,
+ an open source file syncing & sharing software. Available
+ as
+ services.seafile.
+
+
diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md
index 0ddbfc5ab813..e02fbb9ea314 100644
--- a/nixos/doc/manual/release-notes/rl-2111.section.md
+++ b/nixos/doc/manual/release-notes/rl-2111.section.md
@@ -114,6 +114,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [multipath](https://github.com/opensvc/multipath-tools), the device mapper multipath (DM-MP) daemon. Available as [services.multipath](#opt-services.multipath.enable).
+- [seafile](https://www.seafile.com/en/home/), an open source file syncing & sharing software. Available as [services.seafile](options.html#opt-services.seafile.enable).
+
## Backward Incompatibilities {#sec-release-21.11-incompatibilities}
- The `services.wakeonlan` option was removed, and replaced with `networking.interfaces..wakeOnLan`.
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 41a7db17c328..9343f2dbc847 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -838,6 +838,7 @@
./services/networking/rpcbind.nix
./services/networking/rxe.nix
./services/networking/sabnzbd.nix
+ ./services/networking/seafile.nix
./services/networking/searx.nix
./services/networking/skydns.nix
./services/networking/shadowsocks.nix
diff --git a/nixos/modules/services/networking/seafile.nix b/nixos/modules/services/networking/seafile.nix
new file mode 100644
index 000000000000..856797b6b020
--- /dev/null
+++ b/nixos/modules/services/networking/seafile.nix
@@ -0,0 +1,290 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ python = pkgs.python3Packages.python;
+ cfg = config.services.seafile;
+ settingsFormat = pkgs.formats.ini { };
+
+ ccnetConf = settingsFormat.generate "ccnet.conf" cfg.ccnetSettings;
+
+ seafileConf = settingsFormat.generate "seafile.conf" cfg.seafileSettings;
+
+ seahubSettings = pkgs.writeText "seahub_settings.py" ''
+ FILE_SERVER_ROOT = '${cfg.ccnetSettings.General.SERVICE_URL}/seafhttp'
+ DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': '${seahubDir}/seahub.db',
+ }
+ }
+ MEDIA_ROOT = '${seahubDir}/media/'
+ THUMBNAIL_ROOT = '${seahubDir}/thumbnail/'
+
+ with open('${seafRoot}/.seahubSecret') as f:
+ SECRET_KEY = f.readline().rstrip()
+
+ ${cfg.seahubExtraConf}
+ '';
+
+ seafRoot = "/var/lib/seafile"; # hardcode it due to dynamicuser
+ ccnetDir = "${seafRoot}/ccnet";
+ dataDir = "${seafRoot}/data";
+ seahubDir = "${seafRoot}/seahub";
+
+in {
+
+ ###### Interface
+
+ options.services.seafile = {
+ enable = mkEnableOption "Seafile server";
+
+ ccnetSettings = mkOption {
+ type = types.submodule {
+ freeformType = settingsFormat.type;
+
+ options = {
+ General = {
+ SERVICE_URL = mkOption {
+ type = types.str;
+ example = "https://www.example.com";
+ description = ''
+ Seahub public URL.
+ '';
+ };
+ };
+ };
+ };
+ default = { };
+ description = ''
+ Configuration for ccnet, see
+
+ for supported values.
+ '';
+ };
+
+ seafileSettings = mkOption {
+ type = types.submodule {
+ freeformType = settingsFormat.type;
+
+ options = {
+ fileserver = {
+ port = mkOption {
+ type = types.port;
+ default = 8082;
+ description = ''
+ The tcp port used by seafile fileserver.
+ '';
+ };
+ host = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ example = "0.0.0.0";
+ description = ''
+ The binding address used by seafile fileserver.
+ '';
+ };
+ };
+ };
+ };
+ default = { };
+ description = ''
+ Configuration for seafile-server, see
+
+ for supported values.
+ '';
+ };
+
+ workers = mkOption {
+ type = types.int;
+ default = 4;
+ example = 10;
+ description = ''
+ The number of gunicorn worker processes for handling requests.
+ '';
+ };
+
+ adminEmail = mkOption {
+ example = "john@example.com";
+ type = types.str;
+ description = ''
+ Seafile Seahub Admin Account Email.
+ '';
+ };
+
+ initialAdminPassword = mkOption {
+ example = "someStrongPass";
+ type = types.str;
+ description = ''
+ Seafile Seahub Admin Account initial password.
+ Should be change via Seahub web front-end.
+ '';
+ };
+
+ seafilePackage = mkOption {
+ type = types.package;
+ description = "Which package to use for the seafile server.";
+ default = pkgs.seafile-server;
+ };
+
+ seahubExtraConf = mkOption {
+ default = "";
+ type = types.lines;
+ description = ''
+ Extra config to append to `seahub_settings.py` file.
+ Refer to
+ for all available options.
+ '';
+ };
+ };
+
+ ###### Implementation
+
+ config = mkIf cfg.enable {
+
+ environment.etc."seafile/ccnet.conf".source = ccnetConf;
+ environment.etc."seafile/seafile.conf".source = seafileConf;
+ environment.etc."seafile/seahub_settings.py".source = seahubSettings;
+
+ systemd.targets.seafile = {
+ wantedBy = [ "multi-user.target" ];
+ description = "Seafile components";
+ };
+
+ systemd.services = let
+ securityOptions = {
+ ProtectHome = true;
+ PrivateUsers = true;
+ PrivateDevices = true;
+ ProtectClock = true;
+ ProtectHostname = true;
+ ProtectProc = "invisible";
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectKernelLogs = true;
+ ProtectControlGroups = true;
+ RestrictNamespaces = true;
+ LockPersonality = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ MemoryDenyWriteExecute = true;
+ SystemCallArchitectures = "native";
+ RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" ];
+ };
+ in {
+ seaf-server = {
+ description = "Seafile server";
+ partOf = [ "seafile.target" ];
+ after = [ "network.target" ];
+ wantedBy = [ "seafile.target" ];
+ restartTriggers = [ ccnetConf seafileConf ];
+ serviceConfig = securityOptions // {
+ User = "seafile";
+ Group = "seafile";
+ DynamicUser = true;
+ StateDirectory = "seafile";
+ RuntimeDirectory = "seafile";
+ LogsDirectory = "seafile";
+ ConfigurationDirectory = "seafile";
+ ExecStart = ''
+ ${cfg.seafilePackage}/bin/seaf-server \
+ --foreground \
+ -F /etc/seafile \
+ -c ${ccnetDir} \
+ -d ${dataDir} \
+ -l /var/log/seafile/server.log \
+ -P /run/seafile/server.pid \
+ -p /run/seafile
+ '';
+ };
+ preStart = ''
+ if [ ! -f "${seafRoot}/server-setup" ]; then
+ mkdir -p ${dataDir}/library-template
+ mkdir -p ${ccnetDir}/{GroupMgr,misc,OrgMgr,PeerMgr}
+ ${pkgs.sqlite}/bin/sqlite3 ${ccnetDir}/GroupMgr/groupmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/groupmgr.sql"
+ ${pkgs.sqlite}/bin/sqlite3 ${ccnetDir}/misc/config.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/config.sql"
+ ${pkgs.sqlite}/bin/sqlite3 ${ccnetDir}/OrgMgr/orgmgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/org.sql"
+ ${pkgs.sqlite}/bin/sqlite3 ${ccnetDir}/PeerMgr/usermgr.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/user.sql"
+ ${pkgs.sqlite}/bin/sqlite3 ${dataDir}/seafile.db ".read ${cfg.seafilePackage}/share/seafile/sql/sqlite/seafile.sql"
+ echo "${cfg.seafilePackage.version}-sqlite" > "${seafRoot}"/server-setup
+ fi
+ # checking for upgrades and handling them
+ # WARNING: needs to be extended to actually handle major version migrations
+ installedMajor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f1)
+ installedMinor=$(cat "${seafRoot}/server-setup" | cut -d"-" -f1 | cut -d"." -f2)
+ pkgMajor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f1)
+ pkgMinor=$(echo "${cfg.seafilePackage.version}" | cut -d"." -f2)
+ if [ $installedMajor != $pkgMajor ] || [ $installedMinor != $pkgMinor ]; then
+ echo "Unsupported upgrade" >&2
+ exit 1
+ fi
+ '';
+ };
+
+ seahub = let
+ penv = (pkgs.python3.withPackages (ps: with ps; [ gunicorn seahub ]));
+ in {
+ description = "Seafile Server Web Frontend";
+ wantedBy = [ "seafile.target" ];
+ partOf = [ "seafile.target" ];
+ after = [ "network.target" "seaf-server.service" ];
+ requires = [ "seaf-server.service" ];
+ restartTriggers = [ seahubSettings ];
+ environment = {
+ PYTHONPATH =
+ "${pkgs.python3Packages.seahub}/thirdpart:${pkgs.python3Packages.seahub}:${penv}/${python.sitePackages}";
+ DJANGO_SETTINGS_MODULE = "seahub.settings";
+ CCNET_CONF_DIR = ccnetDir;
+ SEAFILE_CONF_DIR = dataDir;
+ SEAFILE_CENTRAL_CONF_DIR = "/etc/seafile";
+ SEAFILE_RPC_PIPE_PATH = "/run/seafile";
+ SEAHUB_LOG_DIR = "/var/log/seafile";
+ };
+ serviceConfig = securityOptions // {
+ User = "seafile";
+ Group = "seafile";
+ DynamicUser = true;
+ RuntimeDirectory = "seahub";
+ StateDirectory = "seafile";
+ LogsDirectory = "seafile";
+ ConfigurationDirectory = "seafile";
+ ExecStart = ''
+ ${penv}/bin/gunicorn seahub.wsgi:application \
+ --name seahub \
+ --workers ${toString cfg.workers} \
+ --log-level=info \
+ --preload \
+ --timeout=1200 \
+ --limit-request-line=8190 \
+ --bind unix:/run/seahub/gunicorn.sock
+ '';
+ };
+ preStart = ''
+ mkdir -p ${seahubDir}/media
+ # Link all media except avatars
+ for m in `find ${pkgs.python3Packages.seahub}/media/ -maxdepth 1 -not -name "avatars"`; do
+ ln -sf $m ${seahubDir}/media/
+ done
+ if [ ! -e "${seafRoot}/.seahubSecret" ]; then
+ ${penv}/bin/python ${pkgs.python3Packages.seahub}/tools/secret_key_generator.py > ${seafRoot}/.seahubSecret
+ chmod 400 ${seafRoot}/.seahubSecret
+ fi
+ if [ ! -f "${seafRoot}/seahub-setup" ]; then
+ # avatars directory should be writable
+ install -D -t ${seahubDir}/media/avatars/ ${pkgs.python3Packages.seahub}/media/avatars/default.png
+ install -D -t ${seahubDir}/media/avatars/groups ${pkgs.python3Packages.seahub}/media/avatars/groups/default.png
+ # init database
+ ${pkgs.python3Packages.seahub}/manage.py migrate
+ # create admin account
+ ${pkgs.expect}/bin/expect -c 'spawn ${pkgs.python3Packages.seahub}/manage.py createsuperuser --email=${cfg.adminEmail}; expect "Password: "; send "${cfg.initialAdminPassword}\r"; expect "Password (again): "; send "${cfg.initialAdminPassword}\r"; expect "Superuser created successfully."'
+ echo "${pkgs.python3Packages.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
+ fi
+ if [ $(cat "${seafRoot}/seahub-setup" | cut -d"-" -f1) != "${pkgs.python3Packages.seahub.version}" ]; then
+ # update database
+ ${pkgs.python3Packages.seahub}/manage.py migrate
+ echo "${pkgs.python3Packages.seahub.version}-sqlite" > "${seafRoot}/seahub-setup"
+ fi
+ '';
+ };
+ };
+ };
+}
diff --git a/nixos/tests/seafile.nix b/nixos/tests/seafile.nix
new file mode 100644
index 000000000000..17862cff189e
--- /dev/null
+++ b/nixos/tests/seafile.nix
@@ -0,0 +1,123 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+ let
+ client = { config, pkgs, ... }: {
+ virtualisation.memorySize = 256;
+ environment.systemPackages = [ pkgs.seafile-shared pkgs.curl ];
+ };
+ in {
+ name = "seafile";
+ meta = with pkgs.stdenv.lib.maintainers; {
+ maintainers = [ kampfschlaefer schmittlauch ];
+ };
+
+ nodes = {
+ server = { config, pkgs, ... }: {
+ virtualisation.memorySize = 512;
+ services.seafile = {
+ enable = true;
+ ccnetSettings.General.SERVICE_URL = "http://server";
+ adminEmail = "admin@example.com";
+ initialAdminPassword = "seafile_password";
+ };
+ services.nginx = {
+ enable = true;
+ virtualHosts."server" = {
+ locations."/".proxyPass = "http://unix:/run/seahub/gunicorn.sock";
+ locations."/seafhttp" = {
+ proxyPass = "http://127.0.0.1:8082";
+ extraConfig = ''
+ rewrite ^/seafhttp(.*)$ $1 break;
+ client_max_body_size 0;
+ proxy_connect_timeout 36000s;
+ proxy_read_timeout 36000s;
+ proxy_send_timeout 36000s;
+ send_timeout 36000s;
+ proxy_http_version 1.1;
+ '';
+ };
+ };
+ };
+ networking.firewall = { allowedTCPPorts = [ 80 ]; };
+ };
+ client1 = client pkgs;
+ client2 = client pkgs;
+ };
+
+ testScript = ''
+ start_all()
+
+ with subtest("start seaf-server"):
+ server.wait_for_unit("seaf-server.service")
+ server.wait_for_file("/run/seafile/seafile.sock")
+
+ with subtest("start seahub"):
+ server.wait_for_unit("seahub.service")
+ server.wait_for_unit("nginx.service")
+ server.wait_for_file("/run/seahub/gunicorn.sock")
+
+ with subtest("client1 fetch seahub page"):
+ client1.succeed("curl -L http://server | grep 'Log In' >&2")
+
+ with subtest("client1 connect"):
+ client1.wait_for_unit("default.target")
+ client1.succeed("seaf-cli init -d . >&2")
+ client1.succeed("seaf-cli start >&2")
+ client1.succeed(
+ "seaf-cli list-remote -s http://server -u admin\@example.com -p seafile_password >&2"
+ )
+
+ libid = client1.succeed(
+ 'seaf-cli create -s http://server -n test01 -u admin\@example.com -p seafile_password -t "first test library"'
+ ).strip()
+
+ client1.succeed(
+ "seaf-cli list-remote -s http://server -u admin\@example.com -p seafile_password |grep test01"
+ )
+ client1.fail(
+ "seaf-cli list-remote -s http://server -u admin\@example.com -p seafile_password |grep test02"
+ )
+
+ client1.succeed(
+ f"seaf-cli download -l {libid} -s http://server -u admin\@example.com -p seafile_password -d . >&2"
+ )
+
+ client1.sleep(3)
+
+ client1.succeed("seaf-cli status |grep synchronized >&2")
+
+ client1.succeed("ls -la >&2")
+ client1.succeed("ls -la test01 >&2")
+
+ client1.execute("echo bla > test01/first_file")
+
+ client1.sleep(2)
+
+ client1.succeed("seaf-cli status |grep synchronized >&2")
+
+ with subtest("client2 sync"):
+ client2.wait_for_unit("default.target")
+
+ client2.succeed("seaf-cli init -d . >&2")
+ client2.succeed("seaf-cli start >&2")
+
+ client2.succeed(
+ "seaf-cli list-remote -s http://server -u admin\@example.com -p seafile_password >&2"
+ )
+
+ libid = client2.succeed(
+ "seaf-cli list-remote -s http://server -u admin\@example.com -p seafile_password |grep test01 |cut -d' ' -f 2"
+ ).strip()
+
+ client2.succeed(
+ f"seaf-cli download -l {libid} -s http://server -u admin\@example.com -p seafile_password -d . >&2"
+ )
+
+ client2.sleep(3)
+
+ client2.succeed("seaf-cli status |grep synchronized >&2")
+
+ client2.succeed("ls -la test01 >&2")
+
+ client2.succeed('[ `cat test01/first_file` = "bla" ]')
+ '';
+ })
diff --git a/pkgs/development/libraries/oniguruma/default.nix b/pkgs/development/libraries/oniguruma/default.nix
index 1968e76274bf..e50750d58ec0 100644
--- a/pkgs/development/libraries/oniguruma/default.nix
+++ b/pkgs/development/libraries/oniguruma/default.nix
@@ -12,6 +12,7 @@ stdenv.mkDerivation rec {
};
nativeBuildInputs = [ autoreconfHook ];
+ configureFlags = [ "--enable-posix-api=yes" ];
meta = with lib; {
homepage = "https://github.com/kkos/oniguruma";
diff --git a/pkgs/development/python-modules/django-formtools/default.nix b/pkgs/development/python-modules/django-formtools/default.nix
new file mode 100644
index 000000000000..faca36c2a98b
--- /dev/null
+++ b/pkgs/development/python-modules/django-formtools/default.nix
@@ -0,0 +1,23 @@
+{ stdenv, lib, buildPythonPackage, fetchPypi, django, python }:
+
+buildPythonPackage rec {
+ pname = "django-formtools";
+ version = "2.2";
+
+ src = fetchPypi {
+ inherit pname version;
+ sha256 = "1chkbl188yj6hvhh1wgjpfgql553k6hrfwxzb8vv4lfdq41jq9y5";
+ };
+
+ propagatedBuildInputs = [ django ];
+ checkPhase = ''
+ ${python.interpreter} -m django test --settings=tests.settings
+ '';
+
+ meta = with lib; {
+ description = "A set of high-level abstractions for Django forms";
+ homepage = "https://github.com/jazzband/django-formtools";
+ license = licenses.bsd3;
+ maintainers = with maintainers; [ greizgh schmittlauch ];
+ };
+}
diff --git a/pkgs/development/python-modules/django-statici18n/default.nix b/pkgs/development/python-modules/django-statici18n/default.nix
new file mode 100644
index 000000000000..88c63319a89d
--- /dev/null
+++ b/pkgs/development/python-modules/django-statici18n/default.nix
@@ -0,0 +1,24 @@
+{ stdenv, lib, buildPythonPackage, fetchPypi, django, django_appconf }:
+
+buildPythonPackage rec {
+ pname = "django-statici18n";
+ version = "2.0.1";
+
+ src = fetchPypi {
+ inherit pname version;
+ sha256 = "0cqwfirzjbanibq3mfz9lcwqnc8655zpysf9hk9g3lbwj2m478sp";
+ };
+
+ propagatedBuildInputs = [ django django_appconf ];
+
+ # pypi package does not contains test harness
+ # source tarball requires setting up a config
+ doCheck = false;
+
+ meta = with lib; {
+ description = "Helper for generating Javascript catalog to static files";
+ homepage = "https://github.com/zyegfryed/django-statici18n";
+ license = licenses.bsd3;
+ maintainers = with maintainers; [ greizgh schmittlauch ];
+ };
+}
diff --git a/pkgs/development/python-modules/seahub/default.nix b/pkgs/development/python-modules/seahub/default.nix
new file mode 100644
index 000000000000..3ed0d9acfedc
--- /dev/null
+++ b/pkgs/development/python-modules/seahub/default.nix
@@ -0,0 +1,56 @@
+{ stdenv, lib, fetchFromGitHub, python3Packages, makeWrapper }:
+
+python3Packages.buildPythonPackage rec {
+ pname = "seahub";
+ version = "8.0.7";
+
+ src = fetchFromGitHub {
+ owner = "haiwen";
+ repo = "seahub";
+ rev = "4f7bb3f617dd847cf0a6b33c0bfb567b44c06059"; # using a fixed revision because upstream may re-tag releases :/
+ sha256 = "09d05sxly1bljxxzm77limhwsbg8c4b54fzv3kmaih59pjnjyr03";
+ };
+
+ dontBuild = true;
+ doCheck = false; # disabled because it requires a ccnet environment
+
+ nativeBuildInputs = [ makeWrapper ];
+
+ propagatedBuildInputs = with python3Packages; [
+ django
+ future
+ django-statici18n
+ django-webpack-loader
+ django-simple-captcha
+ django-picklefield
+ django-formtools
+ mysqlclient
+ pillow
+ python-dateutil
+ django_compressor
+ djangorestframework
+ openpyxl
+ requests
+ requests_oauthlib
+ pyjwt
+ pycryptodome
+ qrcode
+ pysearpc
+ seaserv
+ ];
+
+ installPhase = ''
+ cp -dr --no-preserve='ownership' . $out/
+ wrapProgram $out/manage.py \
+ --prefix PYTHONPATH : "$PYTHONPATH:$out/thirdpart:" \
+ --prefix PATH : "${python3Packages.python}/bin"
+ '';
+
+ meta = with lib; {
+ homepage = "https://github.com/haiwen/seahub";
+ description = "The web end of seafile server";
+ license = licenses.asl20;
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ greizgh schmittlauch ];
+ };
+}
diff --git a/pkgs/misc/seafile-shared/default.nix b/pkgs/misc/seafile-shared/default.nix
index cc6d0ced6d1b..6db3ab932db9 100644
--- a/pkgs/misc/seafile-shared/default.nix
+++ b/pkgs/misc/seafile-shared/default.nix
@@ -18,8 +18,8 @@ stdenv.mkDerivation rec {
src = fetchFromGitHub {
owner = "haiwen";
repo = "seafile";
- rev = "v${version}";
- sha256 = "QflLh3fj+jOq/8etr9aG8LGrvtIlB/htVkWbdO+GIbM=";
+ rev = "0fdc14d5175979919b7c741f6bb97bfaaacbbfbe";
+ sha256 = "1cr1hvpp96s5arnzh1r5sazapcghhvbazbf7zym37yp3fy3lpya1";
};
nativeBuildInputs = [
@@ -40,12 +40,12 @@ stdenv.mkDerivation rec {
configureFlags = [
"--disable-server"
- "--disable-console"
"--with-python3"
];
pythonPath = with python3.pkgs; [
- libsearpc
+ future
+ pysearpc
];
postFixup = ''
@@ -55,8 +55,8 @@ stdenv.mkDerivation rec {
meta = with lib; {
homepage = "https://github.com/haiwen/seafile";
description = "Shared components of Seafile: seafile-daemon, libseafile, libseafile python bindings, manuals, and icons";
- license = licenses.gpl3;
+ license = licenses.gpl2Plus;
platforms = platforms.linux;
- maintainers = [ ];
+ maintainers = with maintainers; [ greizgh schmittlauch ];
};
}
diff --git a/pkgs/servers/seafile-server/default.nix b/pkgs/servers/seafile-server/default.nix
new file mode 100644
index 000000000000..d60dd7809913
--- /dev/null
+++ b/pkgs/servers/seafile-server/default.nix
@@ -0,0 +1,52 @@
+{ stdenv, lib, fetchFromGitHub, pkg-config, python3Packages, autoreconfHook
+, libuuid, sqlite, glib, libevent, libsearpc, openssl, fuse, libarchive, which
+, vala, cmake, oniguruma }:
+
+let
+ # seafile-server relies on a specific version of libevhtp.
+ # It contains non upstreamed patches and is forked off an outdated version.
+ libevhtp = import ./libevhtp.nix {
+ inherit stdenv lib fetchFromGitHub cmake libevent;
+ };
+in stdenv.mkDerivation rec {
+ pname = "seafile-server";
+ version = "8.0.7";
+
+ src = fetchFromGitHub {
+ owner = "haiwen";
+ repo = "seafile-server";
+ rev = "27dac89bb3a81c5acc3f764ce92134eb357ea64b";
+ sha256 = "1h2hxvv0l5m9nbkdyjpznb7ddk8hb8hhwj8b2lx6aqbvp8gll9q7";
+ };
+
+ nativeBuildInputs = [ autoreconfHook pkg-config ];
+
+ buildInputs = [
+ libuuid
+ sqlite
+ openssl
+ glib
+ libsearpc
+ libevent
+ python3Packages.python
+ fuse
+ libarchive
+ which
+ vala
+ libevhtp
+ oniguruma
+ ];
+
+ postInstall = ''
+ mkdir -p $out/share/seafile/sql
+ cp -r scripts/sql $out/share/seafile
+ '';
+
+ meta = with lib; {
+ description = "File syncing and sharing software with file encryption and group sharing, emphasis on reliability and high performance";
+ homepage = "https://github.com/haiwen/seafile-server";
+ license = licenses.agpl3Plus;
+ platforms = platforms.linux;
+ maintainers = with maintainers; [ greizgh schmittlauch ];
+ };
+}
diff --git a/pkgs/servers/seafile-server/libevhtp.nix b/pkgs/servers/seafile-server/libevhtp.nix
new file mode 100644
index 000000000000..97cdc0804faa
--- /dev/null
+++ b/pkgs/servers/seafile-server/libevhtp.nix
@@ -0,0 +1,29 @@
+{ stdenv, lib, fetchFromGitHub, cmake, libevent }:
+
+stdenv.mkDerivation rec {
+ pname = "libevhtp";
+ version = "unstable-2021-04-28";
+
+ src = fetchFromGitHub {
+ owner = "haiwen";
+ repo = "libevhtp";
+ rev = "18c649203f009ef1d77d6f8301eba09af3777adf";
+ sha256 = "1rf0jcy2lf8jbzpkhfgv289hc8zdy5zs6sn36k4vlqvilginxiid";
+ };
+
+ nativeBuildInputs = [ cmake ];
+
+ buildInputs = [ libevent ];
+
+ cmakeFlags = [
+ "-DEVHTP_DISABLE_SSL=ON"
+ "-DEVHTP_BUILD_SHARED=ON"
+ ];
+
+ meta = with lib; {
+ description = "Create extremely-fast and secure embedded HTTP servers with ease";
+ homepage = "https://github.com/criticalstack/libevhtp";
+ license = licenses.bsd3;
+ maintainers = with maintainers; [ greizgh schmittlauch ];
+ };
+}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 29b44acfc8a0..f111f9dbd7d4 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -32676,6 +32676,8 @@ with pkgs;
thrift = thrift-0_10;
};
+ seafile-server = callPackage ../servers/seafile-server { };
+
seafile-shared = callPackage ../misc/seafile-shared { };
ser2net = callPackage ../servers/ser2net {};
diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index 7b303aa4b307..f355534dc77e 100644
--- a/pkgs/top-level/python-packages.nix
+++ b/pkgs/top-level/python-packages.nix
@@ -2110,6 +2110,8 @@ in {
django-filter = callPackage ../development/python-modules/django-filter { };
+ django-formtools = callPackage ../development/python-modules/django-formtools { };
+
django-gravatar2 = callPackage ../development/python-modules/django-gravatar2 { };
django_guardian = callPackage ../development/python-modules/django_guardian { };
@@ -2179,6 +2181,8 @@ in {
django-sr = callPackage ../development/python-modules/django-sr { };
+ django-statici18n = callPackage ../development/python-modules/django-statici18n { };
+
django-storages = callPackage ../development/python-modules/django-storages { };
django_tagging = callPackage ../development/python-modules/django_tagging { };
@@ -6956,6 +6960,8 @@ in {
pysdl2 = callPackage ../development/python-modules/pysdl2 { };
+ pysearpc = toPythonModule pkgs.libsearpc;
+
pysendfile = callPackage ../development/python-modules/pysendfile { };
pysensors = callPackage ../development/python-modules/pysensors { };
@@ -8319,6 +8325,10 @@ in {
seabreeze = callPackage ../development/python-modules/seabreeze { };
+ seahub = callPackage ../development/python-modules/seahub { };
+
+ seaserv = toPythonModule pkgs.seafile-server;
+
seccomp = callPackage ../development/python-modules/seccomp { };
secp256k1 = callPackage ../development/python-modules/secp256k1 {