From c9ddb6bef5f3760d3921969f241cb93b1162c32b Mon Sep 17 00:00:00 2001 From: Gaetan Lepage Date: Thu, 2 Jan 2025 23:56:15 +0100 Subject: [PATCH 01/58] linuxPackages: 6.6 -> 6.12 The latest longterm kernel release series is 6.12, and we should roll it out as the default now, to receive as much testing as possible before the NixOS 25.05 release. --- nixos/doc/manual/release-notes/rl-2505.section.md | 2 ++ pkgs/top-level/linux-kernels.nix | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index f62e45e040e1..abd771f2dfaa 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -10,6 +10,8 @@ Users on old macOS versions should consider upgrading to a supported version (potentially using [OpenCore Legacy Patcher](https://dortania.github.io/OpenCore-Legacy-Patcher/) for old hardware) or installing NixOS. If neither of those options are viable and you require new versions of software, [MacPorts](https://www.macports.org/) supports versions back to Mac OS X Snow Leopard 10.6. +- The default kernel package has been updated from 6.6 to 6.12. All supported kernels remain available. + - GCC has been updated from GCC 13 to GCC 14. This introduces some backwards‐incompatible changes; see the [upstream porting guide](https://gcc.gnu.org/gcc-14/porting_to.html) for details. diff --git a/pkgs/top-level/linux-kernels.nix b/pkgs/top-level/linux-kernels.nix index 0eed40c970a8..f223cf4e97be 100644 --- a/pkgs/top-level/linux-kernels.nix +++ b/pkgs/top-level/linux-kernels.nix @@ -704,7 +704,7 @@ in { }); packageAliases = { - linux_default = packages.linux_6_6; + linux_default = packages.linux_6_12; # Update this when adding the newest kernel major version! linux_latest = packages.linux_6_12; linux_rt_default = packages.linux_rt_5_15; From cec9f3032be7547b18ea43fd16882691ffb6782f Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 02/58] paulstretch: update homepage --- pkgs/by-name/pa/paulstretch/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/pa/paulstretch/package.nix b/pkgs/by-name/pa/paulstretch/package.nix index 18648c5e5f30..756b2e99d73a 100644 --- a/pkgs/by-name/pa/paulstretch/package.nix +++ b/pkgs/by-name/pa/paulstretch/package.nix @@ -66,7 +66,7 @@ stdenv.mkDerivation { special effects by "spectral smoothing" the sounds. It can transform any sound/music to a texture. ''; - homepage = "https://hypermammut.sourceforge.net/paulstretch/"; + homepage = "https://github.com/paulnasca/paulstretch_cpp/"; platforms = platforms.linux; license = licenses.gpl2; mainProgram = "paulstretch"; From bb5d69bba9f648a1a0897383327f1fb89858c53c Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 03/58] aragorn: update homepage --- pkgs/by-name/ar/aragorn/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/ar/aragorn/package.nix b/pkgs/by-name/ar/aragorn/package.nix index 23a7c12d927c..5f0d71683a8f 100644 --- a/pkgs/by-name/ar/aragorn/package.nix +++ b/pkgs/by-name/ar/aragorn/package.nix @@ -46,7 +46,7 @@ stdenv.mkDerivation (finalAttrs: { meta = with lib; { description = "Detects tRNA, mtRNA, and tmRNA genes in nucleotide sequences"; mainProgram = "aragorn"; - homepage = "http://www.ansikte.se/ARAGORN/"; + homepage = "https://www.trna.se/ARAGORN/"; license = licenses.gpl3Plus; maintainers = [ maintainers.bzizou ]; platforms = platforms.unix; From 0beaedaca95e04759bb1847d34b2f0988e08c5cc Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 04/58] netperf: update homepage --- pkgs/by-name/ne/netperf/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/ne/netperf/package.nix b/pkgs/by-name/ne/netperf/package.nix index 338b645556d8..53081ccff956 100644 --- a/pkgs/by-name/ne/netperf/package.nix +++ b/pkgs/by-name/ne/netperf/package.nix @@ -41,7 +41,7 @@ stdenv.mkDerivation { meta = { description = "Benchmark to measure the performance of many different types of networking"; - homepage = "http://www.netperf.org/netperf/"; + homepage = "https://github.com/HewlettPackard/netperf/"; license = lib.licenses.mit; platforms = lib.platforms.unix; From f2e6d6ab9cd59898adbdbf3e61bd4728813a6267 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 05/58] vengi-tools: update homepage --- pkgs/applications/graphics/vengi-tools/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/applications/graphics/vengi-tools/default.nix b/pkgs/applications/graphics/vengi-tools/default.nix index b4a99396fb97..47be62abfe35 100644 --- a/pkgs/applications/graphics/vengi-tools/default.nix +++ b/pkgs/applications/graphics/vengi-tools/default.nix @@ -39,7 +39,7 @@ stdenv.mkDerivation (finalAttrs: { version = "0.0.34"; src = fetchFromGitHub { - owner = "mgerhardy"; + owner = "vengi-voxel"; repo = "vengi"; rev = "v${finalAttrs.version}"; hash = "sha256-a78Oiwln3vyzCyjNewbK1/05bnGcSixxzKIgz4oiDmA="; @@ -114,8 +114,8 @@ stdenv.mkDerivation (finalAttrs: { filemanager and a command line tool to convert between several voxel formats. ''; - homepage = "https://mgerhardy.github.io/vengi/"; - downloadPage = "https://github.com/mgerhardy/vengi/releases"; + homepage = "https://vengi-voxel.github.io/vengi/"; + downloadPage = "https://github.com/vengi-voxel/vengi/releases"; license = [ licenses.mit licenses.cc-by-sa-30 From 3e071e122ab13da7c3b33e949fec2288b1c35b97 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 06/58] iwona: update homepage --- pkgs/by-name/iw/iwona/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/iw/iwona/package.nix b/pkgs/by-name/iw/iwona/package.nix index 49f6ffc13441..c6bb9fec58d7 100644 --- a/pkgs/by-name/iw/iwona/package.nix +++ b/pkgs/by-name/iw/iwona/package.nix @@ -20,7 +20,7 @@ stdenvNoCC.mkDerivation rec { meta = with lib; { description = "Two-element sans-serif typeface, created by Małgorzata Budyta"; - homepage = "https://jmn.pl/en/kurier-i-iwona/"; + homepage = "https://jmn.pl/en/kurier/"; # "[...] GUST Font License (GFL), which is a free license, legally # equivalent to the LaTeX Project Public # License (LPPL), version 1.3c or # later." - GUST website From a3e6095949acaefb81ea348aced6a0ee22b91148 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 07/58] garden-of-coloured-lights: update homepage --- pkgs/games/garden-of-coloured-lights/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/games/garden-of-coloured-lights/default.nix b/pkgs/games/garden-of-coloured-lights/default.nix index a26cea279612..77e252633532 100644 --- a/pkgs/games/garden-of-coloured-lights/default.nix +++ b/pkgs/games/garden-of-coloured-lights/default.nix @@ -36,7 +36,7 @@ stdenv.mkDerivation rec { meta = with lib; { description = "Old-school vertical shoot-em-up / bullet hell"; mainProgram = "garden"; - homepage = "https://garden.sourceforge.net/drupal/"; + homepage = "https://sourceforge.net/projects/garden/"; maintainers = [ ]; license = licenses.gpl3; }; From 0f53540942c196a86b03a161584f012b93ec4a2f Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 08/58] midori-unwrapped: update homepage --- pkgs/by-name/mi/midori-unwrapped/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/mi/midori-unwrapped/package.nix b/pkgs/by-name/mi/midori-unwrapped/package.nix index 70f3d294493d..855f54c87aa4 100644 --- a/pkgs/by-name/mi/midori-unwrapped/package.nix +++ b/pkgs/by-name/mi/midori-unwrapped/package.nix @@ -58,7 +58,7 @@ stdenv.mkDerivation rec { meta = with lib; { description = "Lightweight WebKitGTK web browser"; mainProgram = "midori"; - homepage = "https://www.midori-browser.org/"; + homepage = "https://github.com/midori-browser/core"; license = with licenses; [ lgpl21Plus ]; platforms = with platforms; linux; maintainers = with maintainers; [ From b331d661de5d58572e44d388cd81895d1e645b94 Mon Sep 17 00:00:00 2001 From: boralg Date: Sat, 18 Jan 2025 19:47:47 +0200 Subject: [PATCH 09/58] maintainers: rename thinnerthinker -> boralg --- maintainers/maintainer-list.nix | 10 +++++----- pkgs/by-name/re/repomix/package.nix | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 5b5634a67887..b24d1ca4e1aa 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -3211,6 +3211,11 @@ matrix = "@boozedog:matrix.org"; name = "David A. Buser"; }; + boralg = { + name = "boralg"; + github = "boralg"; + githubId = 144260188; + }; borisbabic = { email = "boris.ivan.babic@gmail.com"; github = "borisbabic"; @@ -22648,11 +22653,6 @@ github = "thilobillerbeck"; githubId = 7442383; }; - thinnerthinker = { - name = "thinnerthinker"; - github = "thinnerthinker"; - githubId = 144260188; - }; thled = { name = "Thomas Le Duc"; email = "dev@tleduc.de"; diff --git a/pkgs/by-name/re/repomix/package.nix b/pkgs/by-name/re/repomix/package.nix index d5c5e01cab0c..70f9a692626d 100644 --- a/pkgs/by-name/re/repomix/package.nix +++ b/pkgs/by-name/re/repomix/package.nix @@ -37,7 +37,7 @@ buildNpmPackage rec { homepage = "https://github.com/yamadashy/repomix"; changelog = "https://github.com/yamadashy/repomix/releases/tag/v${version}"; license = lib.licenses.mit; - maintainers = with lib.maintainers; [ thinnerthinker ]; + maintainers = with lib.maintainers; [ boralg ]; mainProgram = "repomix"; }; } From 10fd8fa7c7f6bb65694bf2abca72707168a00fc3 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Sun, 19 Jan 2025 00:33:09 +0000 Subject: [PATCH 10/58] bfs: 4.0.4 -> 4.0.5 --- pkgs/by-name/bf/bfs/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/bf/bfs/package.nix b/pkgs/by-name/bf/bfs/package.nix index 285b047eaf9b..01f3b1b65965 100644 --- a/pkgs/by-name/bf/bfs/package.nix +++ b/pkgs/by-name/bf/bfs/package.nix @@ -11,13 +11,13 @@ stdenv.mkDerivation rec { pname = "bfs"; - version = "4.0.4"; + version = "4.0.5"; src = fetchFromGitHub { repo = "bfs"; owner = "tavianator"; rev = version; - hash = "sha256-KcXbLYITTxNq2r8Bqf4FRy7cOZw1My9Ii6O/FDLhCGY="; + hash = "sha256-vYK3lQsHE3GD8mFCZLxJN+TrJZJGwq9+kNm6y0zAa2U="; }; buildInputs = From 9aa898f52af4571a4cffad1d4ba704e9f58d637c Mon Sep 17 00:00:00 2001 From: Sam <30577766+Samasaur1@users.noreply.github.com> Date: Sat, 18 Jan 2025 16:41:59 -0800 Subject: [PATCH 11/58] xcodegen: bundle included settings presets --- pkgs/by-name/xc/xcodegen/package.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/by-name/xc/xcodegen/package.nix b/pkgs/by-name/xc/xcodegen/package.nix index d302092be93c..b898315b471a 100644 --- a/pkgs/by-name/xc/xcodegen/package.nix +++ b/pkgs/by-name/xc/xcodegen/package.nix @@ -50,8 +50,9 @@ swiftPackages.stdenv.mkDerivation (finalAttrs: { ''; installPhase = '' - mkdir -p $out/bin + mkdir -p $out/bin $out/share/xcodegen cp "$(swiftpmBinPath)/${finalAttrs.pname}" $out/bin/ + cp -r SettingPresets $out/share/xcodegen/SettingPresets ''; nativeInstallCheckInputs = [ From 47a666c93348704beafe7eae3a63bf3cb13a52ad Mon Sep 17 00:00:00 2001 From: Nikolay Korotkiy Date: Sun, 19 Jan 2025 08:09:34 +0400 Subject: [PATCH 12/58] =?UTF-8?q?tegola:=200.21.0=20=E2=86=92=200.21.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkgs/by-name/te/tegola/package.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/by-name/te/tegola/package.nix b/pkgs/by-name/te/tegola/package.nix index 5ec1f983e343..00ca64faf802 100644 --- a/pkgs/by-name/te/tegola/package.nix +++ b/pkgs/by-name/te/tegola/package.nix @@ -5,13 +5,13 @@ fetchFromGitHub, }: let - version = "0.21.0"; + version = "0.21.2"; src = fetchFromGitHub { owner = "go-spatial"; repo = "tegola"; tag = "v${version}"; - hash = "sha256-EXCh+5t2+7j/huIKUWOqG7u+Lo4eziyvPkDGpw3xaO8="; + hash = "sha256-aJCxxeewOm7DOHmehnsDKoQPwPnUMsjVit41ccY6tLg="; }; frontend = buildNpmPackage { @@ -20,7 +20,7 @@ let src = "${src}/ui"; - npmDepsHash = "sha256-rhUdWt1X5/F0uvT8gI1T9ei6Y+HK1tKj2fuTKlMAwJk="; + npmDepsHash = "sha256-DHJ+l3ceLieGG97kH1ri+7yZAv7R2lVYRdBhjXCy/iM="; installPhase = '' cp -r dist $out From 01e831ecd1566e78bae90cb6936e7d1877ad75d6 Mon Sep 17 00:00:00 2001 From: boralg Date: Sun, 19 Jan 2025 11:18:11 +0200 Subject: [PATCH 13/58] maintainers: add matrix to boralg --- maintainers/maintainer-list.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index b24d1ca4e1aa..97641f1df154 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -3215,6 +3215,7 @@ name = "boralg"; github = "boralg"; githubId = 144260188; + matrix = "@boralg:matrix.org"; }; borisbabic = { email = "boris.ivan.babic@gmail.com"; From bc6541114d2fa114f2bb171e0fa4d434a79190f9 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 14/58] vcprompt: move to pkgs/by-name --- .../vcprompt/default.nix => by-name/vc/vcprompt/package.nix} | 0 pkgs/top-level/all-packages.nix | 4 ---- 2 files changed, 4 deletions(-) rename pkgs/{applications/version-management/vcprompt/default.nix => by-name/vc/vcprompt/package.nix} (100%) diff --git a/pkgs/applications/version-management/vcprompt/default.nix b/pkgs/by-name/vc/vcprompt/package.nix similarity index 100% rename from pkgs/applications/version-management/vcprompt/default.nix rename to pkgs/by-name/vc/vcprompt/package.nix diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index e9c20f5904ff..4901018ce7c0 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -15576,10 +15576,6 @@ with pkgs; valentina = libsForQt5.callPackage ../applications/misc/valentina { }; - vcprompt = callPackage ../applications/version-management/vcprompt { - autoconf = buildPackages.autoconf269; - }; - vdirsyncer = with python3Packages; toPythonApplication vdirsyncer; vengi-tools = darwin.apple_sdk_11_0.callPackage ../applications/graphics/vengi-tools { From c75811f8997dfe6a78929b7a279e8e6393aee764 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Fri, 17 Jan 2025 21:29:18 +0100 Subject: [PATCH 15/58] vcprompt: 1.2.1 -> 1.3.0-unstable-2020-12-28 Use a maintained fork. --- pkgs/by-name/vc/vcprompt/package.nix | 31 +++++++++++++--------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/pkgs/by-name/vc/vcprompt/package.nix b/pkgs/by-name/vc/vcprompt/package.nix index e78c6d5bcaa0..e2dc6dff770b 100644 --- a/pkgs/by-name/vc/vcprompt/package.nix +++ b/pkgs/by-name/vc/vcprompt/package.nix @@ -1,40 +1,37 @@ { lib, stdenv, - fetchhg, - autoconf, + fetchFromGitHub, + autoreconfHook, sqlite, }: stdenv.mkDerivation rec { pname = "vcprompt"; - version = "1.2.1"; + version = "1.3.0-unstable-2020-12-28"; - src = fetchhg { - url = "http://hg.gerg.ca/vcprompt/"; - rev = version; - sha256 = "03xqvp6bfl98bpacrw4n82qv9cw6a4fxci802s3vrygas989v1kj"; + src = fetchFromGitHub { + owner = "powerman"; + repo = "vcprompt"; + rev = "850bf44cd61723f6b46121f678ff94047e42f802"; + hash = "sha256-w2gpekNx3RA7uxNLg0Nkf9/aoxZj3DR4foKI+4q8SKk="; }; + nativeBuildInputs = [ + autoreconfHook + ]; + buildInputs = [ sqlite - autoconf ]; - preConfigure = '' - autoconf - ''; - makeFlags = [ "PREFIX=${placeholder "out"}" ]; meta = with lib; { - description = '' - A little C program that prints a short string with barebones information - about the current working directory for various version control systems - ''; - homepage = "http://hg.gerg.ca/vcprompt"; + description = "Program that prints barebones information about the current working directory for various version control systems"; + homepage = "https://github.com/powerman/vcprompt"; maintainers = [ ]; platforms = with platforms; linux ++ darwin; license = licenses.gpl2Plus; From 1b73a3f88f91120959fd49864d8c823029e91192 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 16/58] sysstat: update homepage --- pkgs/by-name/sy/sysstat/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/sy/sysstat/package.nix b/pkgs/by-name/sy/sysstat/package.nix index a2f59f04fe4a..d8651425fea7 100644 --- a/pkgs/by-name/sy/sysstat/package.nix +++ b/pkgs/by-name/sy/sysstat/package.nix @@ -42,7 +42,7 @@ stdenv.mkDerivation rec { meta = { mainProgram = "iostat"; - homepage = "http://sebastien.godard.pagesperso-orange.fr/"; + homepage = "https://sysstat.github.io/"; description = "Collection of performance monitoring tools for Linux (such as sar, iostat and pidstat)"; license = lib.licenses.gpl2Plus; platforms = lib.platforms.linux; From 4e88251557fb3a7d7942dcaed6e70890606e1b2f Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 17/58] perlPackages.Hailo: update homepage --- pkgs/top-level/perl-packages.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/top-level/perl-packages.nix b/pkgs/top-level/perl-packages.nix index 4403115a5edd..919f2603dfb1 100644 --- a/pkgs/top-level/perl-packages.nix +++ b/pkgs/top-level/perl-packages.nix @@ -11451,7 +11451,7 @@ with self; { ''; meta = { description = "Pluggable Markov engine analogous to MegaHAL"; - homepage = "https://hailo.org"; + homepage = "https://github.com/hailo/hailo"; license = with lib.licenses; [ artistic1 gpl1Plus ]; mainProgram = "hailo"; }; From 660282640d3f816bee07637e523c4646d5709e0f Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 18/58] python312Packages.pyparser: update homepage and src --- pkgs/development/python-modules/pyparser/default.nix | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkgs/development/python-modules/pyparser/default.nix b/pkgs/development/python-modules/pyparser/default.nix index 7b78bf6f27f0..57ce2f2f9d9b 100644 --- a/pkgs/development/python-modules/pyparser/default.nix +++ b/pkgs/development/python-modules/pyparser/default.nix @@ -1,7 +1,7 @@ { buildPythonPackage, lib, - fetchFromBitbucket, + fetchhg, parse, }: @@ -11,9 +11,8 @@ buildPythonPackage rec { format = "setuptools"; # Missing tests on Pypi - src = fetchFromBitbucket { - owner = "rw_grim"; - repo = pname; + src = fetchhg { + url = "https://keep.imfreedom.org/grim/pyparser"; rev = "v${version}"; sha256 = "0aplb4zdpgbpmaw9qj0vr7qip9q5w7sl1m1lp1nc9jmjfij9i0hf"; }; @@ -24,7 +23,7 @@ buildPythonPackage rec { meta = { description = "Simple library that makes it easier to parse files"; - homepage = "https://bitbucket.org/rw_grim/pyparser"; + homepage = "https://keep.imfreedom.org/grim/pyparser"; license = lib.licenses.gpl3; maintainers = [ lib.maintainers.nico202 ]; }; From 63ac80d747ef77daa0559f55c53dd83149e7f900 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 19/58] perlPackages.maatkit: update homepage --- pkgs/development/perl-modules/maatkit/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/development/perl-modules/maatkit/default.nix b/pkgs/development/perl-modules/maatkit/default.nix index 7a0ad7bae4b7..f6793b9bb4a5 100644 --- a/pkgs/development/perl-modules/maatkit/default.nix +++ b/pkgs/development/perl-modules/maatkit/default.nix @@ -43,6 +43,6 @@ buildPerlPackage { growing variety of other databases and technologies. ''; license = licenses.gpl2Plus; - homepage = "http://www.maatkit.org/"; + homepage = "https://code.google.com/archive/p/maatkit/"; }; } From a0936b7bfc0925fce1e306e87ab82bdc185ada0c Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 20/58] cvsps: update homepage --- pkgs/by-name/cv/cvsps/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/cv/cvsps/package.nix b/pkgs/by-name/cv/cvsps/package.nix index cd2d043539d4..055ade25d49e 100644 --- a/pkgs/by-name/cv/cvsps/package.nix +++ b/pkgs/by-name/cv/cvsps/package.nix @@ -64,7 +64,7 @@ stdenv.mkDerivation rec { changes made to a collection of files, and all committed at the same time (using a single "cvs commit" command). ''; - homepage = "http://www.cobite.com/cvsps/"; + homepage = "https://sourceforge.net/projects/cvsps/"; license = lib.licenses.gpl2; platforms = lib.platforms.unix; mainProgram = "cvsps"; From 3e7bfaf54581c0861631da686cb291015945e325 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 21/58] torque: update homepage --- pkgs/servers/computing/torque/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/servers/computing/torque/default.nix b/pkgs/servers/computing/torque/default.nix index 74b5fa8dd043..49210ab7179a 100644 --- a/pkgs/servers/computing/torque/default.nix +++ b/pkgs/servers/computing/torque/default.nix @@ -91,7 +91,7 @@ stdenv.mkDerivation { ''; meta = with lib; { - homepage = "http://www.adaptivecomputing.com/products/open-source/torque"; + homepage = "https://github.com/adaptivecomputing/torque"; description = "Resource management system for submitting and controlling jobs on supercomputers, clusters, and grids"; platforms = platforms.linux; license = "TORQUEv1.1"; From 87c0ae4fc723813f3f86b67d447acc279e4bc4dc Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 22/58] procodile: update homepage --- pkgs/tools/system/procodile/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/tools/system/procodile/default.nix b/pkgs/tools/system/procodile/default.nix index 43faa0af6e59..45a17384e6db 100644 --- a/pkgs/tools/system/procodile/default.nix +++ b/pkgs/tools/system/procodile/default.nix @@ -13,7 +13,7 @@ bundlerApp { meta = with lib; { description = "Run processes in the background (and foreground) on Mac & Linux from a Procfile (for production and/or development environments)"; - homepage = "https://adam.ac/procodile"; + homepage = "https://github.com/adamcooke/procodile"; license = with licenses; mit; maintainers = with maintainers; [ manveru From e0420f93a59b0c65a12ec9497b70be58262a1123 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 23/58] cxxtest: update homepage --- pkgs/development/libraries/cxxtest/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/development/libraries/cxxtest/default.nix b/pkgs/development/libraries/cxxtest/default.nix index ae1e9c302000..b15d9dbe96a2 100644 --- a/pkgs/development/libraries/cxxtest/default.nix +++ b/pkgs/development/libraries/cxxtest/default.nix @@ -42,7 +42,7 @@ python3Packages.buildPythonApplication rec { dontWrapPythonPrograms = true; meta = with lib; { - homepage = "http://cxxtest.com"; + homepage = "http://github.com/CxxTest/cxxtest"; description = "Unit testing framework for C++"; mainProgram = "cxxtestgen"; license = licenses.lgpl3; From d4e33cb80732510f4a262f621616c920a0cf6d87 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 5 Jan 2025 16:08:59 +0100 Subject: [PATCH 24/58] transifex-cli: update homepage --- pkgs/by-name/tr/transifex-cli/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/tr/transifex-cli/package.nix b/pkgs/by-name/tr/transifex-cli/package.nix index a4551be0f8c6..0a46be3e71b3 100644 --- a/pkgs/by-name/tr/transifex-cli/package.nix +++ b/pkgs/by-name/tr/transifex-cli/package.nix @@ -32,7 +32,7 @@ buildGoModule rec { meta = with lib; { description = "Transifex command-line client"; - homepage = "https://github.com/transifex/transifex-cli"; + homepage = "https://github.com/transifex/cli"; license = licenses.asl20; maintainers = with maintainers; [ thornycrackers ]; mainProgram = "tx"; From 3c3982e2231ddf98ceb82ace47b2951421e86fc1 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Sun, 19 Jan 2025 11:39:58 +0000 Subject: [PATCH 25/58] python312Packages.pyexploitdb: 0.2.63 -> 0.2.64 --- pkgs/development/python-modules/pyexploitdb/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/development/python-modules/pyexploitdb/default.nix b/pkgs/development/python-modules/pyexploitdb/default.nix index 843774d365be..8568f1d41452 100644 --- a/pkgs/development/python-modules/pyexploitdb/default.nix +++ b/pkgs/development/python-modules/pyexploitdb/default.nix @@ -10,7 +10,7 @@ buildPythonPackage rec { pname = "pyexploitdb"; - version = "0.2.63"; + version = "0.2.64"; pyproject = true; disabled = pythonOlder "3.7"; @@ -18,7 +18,7 @@ buildPythonPackage rec { src = fetchPypi { pname = "pyExploitDb"; inherit version; - hash = "sha256-PJfbs1qSiumTiHOoffZqag+jVpNbvTOeTpz/peRUlq0="; + hash = "sha256-Os5Sj8zsPCCPxGTdLfiGLJ/tknkDnp9uowWquO31aRQ="; }; build-system = [ setuptools ]; From 69ace4daab664f6d9d48868c08aee8cd654d58f3 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Sun, 19 Jan 2025 12:00:00 +0000 Subject: [PATCH 26/58] paperwork: fix evaluation warning --- pkgs/applications/office/paperwork/src.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/applications/office/paperwork/src.nix b/pkgs/applications/office/paperwork/src.nix index 7038309799e8..84bd20231599 100644 --- a/pkgs/applications/office/paperwork/src.nix +++ b/pkgs/applications/office/paperwork/src.nix @@ -2,12 +2,13 @@ fetchFromGitLab, srcOnly, fetchpatch, + stdenv, }: rec { version = "2.2.5"; src = srcOnly { pname = "paperwork-patched-src"; - inherit version; + inherit version stdenv; src = fetchFromGitLab { domain = "gitlab.gnome.org"; repo = "paperwork"; From 3fb5983a82afd9b395dfd9af88d7e164ba4a66af Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Sun, 19 Jan 2025 14:37:32 +0000 Subject: [PATCH 27/58] python312Packages.minio: 7.2.14 -> 7.2.15 --- pkgs/development/python-modules/minio/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/development/python-modules/minio/default.nix b/pkgs/development/python-modules/minio/default.nix index 8d905c20a7a8..643239ac5a18 100644 --- a/pkgs/development/python-modules/minio/default.nix +++ b/pkgs/development/python-modules/minio/default.nix @@ -22,7 +22,7 @@ buildPythonPackage rec { pname = "minio"; - version = "7.2.14"; + version = "7.2.15"; pyproject = true; disabled = pythonOlder "3.8"; @@ -31,7 +31,7 @@ buildPythonPackage rec { owner = "minio"; repo = "minio-py"; tag = version; - hash = "sha256-FnId8ewKU5+COnrWW6VJWfL7BLij1IIuGOjEWZrPKNQ="; + hash = "sha256-vJ+V8O2fJxG1XpFDwQCmaIT8VTo5pEKduDndg6rzf0s="; }; postPatch = '' From e28b761703108a58dcf7b10d9221213cbad2cdc9 Mon Sep 17 00:00:00 2001 From: WeetHet Date: Sun, 19 Jan 2025 23:17:48 +0200 Subject: [PATCH 28/58] zed-editor: add withGLES to passthru.tests --- pkgs/by-name/ze/zed-editor/package.nix | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pkgs/by-name/ze/zed-editor/package.nix b/pkgs/by-name/ze/zed-editor/package.nix index 5394efcf7073..48a383965144 100644 --- a/pkgs/by-name/ze/zed-editor/package.nix +++ b/pkgs/by-name/ze/zed-editor/package.nix @@ -309,12 +309,16 @@ rustPlatform.buildRustPackage rec { }; fhs = fhs { }; fhsWithPackages = f: fhs { additionalPkgs = f; }; - tests = { - remoteServerVersion = testers.testVersion { - package = zed-editor.remote_server; - command = "zed-remote-server-stable-${version} version"; + tests = + { + remoteServerVersion = testers.testVersion { + package = zed-editor.remote_server; + command = "zed-remote-server-stable-${version} version"; + }; + } + // lib.optionalAttrs stdenv.hostPlatform.isLinux { + withGles = zed-editor.override { withGLES = true; }; }; - }; }; meta = { From 60cc35abae02e10f84f981fe4031092d4a9c75b6 Mon Sep 17 00:00:00 2001 From: Andrew Marshall Date: Tue, 14 Jan 2025 17:21:09 -0500 Subject: [PATCH 29/58] zfs: remove code for obsolete versions In cbc50da11c2dfb45d3ddfe352f24d49c3be81822, ZFS 2.1 was removed, this removes conditional parts of the build only needed for 2.1 and older. --- pkgs/os-specific/linux/zfs/generic.nix | 29 +------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/pkgs/os-specific/linux/zfs/generic.nix b/pkgs/os-specific/linux/zfs/generic.nix index ad6fd902c682..e00db1d6229e 100644 --- a/pkgs/os-specific/linux/zfs/generic.nix +++ b/pkgs/os-specific/linux/zfs/generic.nix @@ -58,7 +58,6 @@ let optionals optional makeBinPath - versionAtLeast ; smartmon = smartmontools.override { inherit enableMail; }; @@ -71,7 +70,6 @@ let "user" "all" ]; - isAtLeast22Series = versionAtLeast version "2.2.0"; # XXX: You always want to build kernel modules with the same stdenv as the # kernel was built with. However, since zfs can also be built for userspace we @@ -121,8 +119,7 @@ let --replace-fail "/etc/default" "$out/etc/default" substituteInPlace ./contrib/initramfs/Makefile.am \ --replace-fail "/usr/share/initramfs-tools" "$out/usr/share/initramfs-tools" - '' - + optionalString isAtLeast22Series '' + substituteInPlace ./udev/vdev_id \ --replace-fail "PATH=/bin:/sbin:/usr/bin:/usr/sbin" \ "PATH=${ @@ -140,24 +137,6 @@ let "bashcompletiondir=$out/share/bash-completion/completions" substituteInPlace ./cmd/arc_summary --replace-fail "/sbin/modinfo" "modinfo" - '' - + optionalString (!isAtLeast22Series) '' - substituteInPlace ./etc/zfs/Makefile.am --replace-fail "\$(sysconfdir)/zfs" "$out/etc/zfs" - - find ./contrib/initramfs -name Makefile.am -exec sed -i -e 's|/usr/share/initramfs-tools|'$out'/share/initramfs-tools|g' {} \; - - substituteInPlace ./cmd/arc_summary/arc_summary3 --replace-fail "/sbin/modinfo" "modinfo" - substituteInPlace ./cmd/vdev_id/vdev_id \ - --replace-fail "PATH=/bin:/sbin:/usr/bin:/usr/sbin" \ - "PATH=${ - makeBinPath [ - coreutils - gawk - gnused - gnugrep - systemd - ] - }" ''; nativeBuildInputs = @@ -260,12 +239,6 @@ let # Remove tests because they add a runtime dependency on gcc rm -rf $out/share/zfs/zfs-tests - - ${optionalString (lib.versionOlder version "2.2") '' - # Add Bash completions. - install -v -m444 -D -t $out/share/bash-completion/completions contrib/bash_completion.d/zfs - (cd $out/share/bash-completion/completions; ln -s zfs zpool) - ''} ''; postFixup = From 5094795c607de240f689ff38787fe58d3b71ed55 Mon Sep 17 00:00:00 2001 From: Andrew Marshall Date: Tue, 14 Jan 2025 13:20:55 -0500 Subject: [PATCH 30/58] zfs: 2.2.7 -> 2.3.0 zfs_2_3 is already packaged, this just changes the default version. --- pkgs/top-level/all-packages.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 42d2f8e9ef91..919d241f3f4b 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -12564,7 +12564,7 @@ with pkgs; zfs_2_2 zfs_2_3 zfs_unstable; - zfs = zfs_2_2; + zfs = zfs_2_3; ### DATA From 3efc691be4709dbbcf79404122feb73cbea083f9 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 01:09:12 +0000 Subject: [PATCH 31/58] nsd: 4.11.0 -> 4.11.1 --- pkgs/servers/dns/nsd/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/servers/dns/nsd/default.nix b/pkgs/servers/dns/nsd/default.nix index fe282767fe89..d6da9df4cc8c 100644 --- a/pkgs/servers/dns/nsd/default.nix +++ b/pkgs/servers/dns/nsd/default.nix @@ -16,11 +16,11 @@ stdenv.mkDerivation rec { pname = "nsd"; - version = "4.11.0"; + version = "4.11.1"; src = fetchurl { url = "https://www.nlnetlabs.nl/downloads/${pname}/${pname}-${version}.tar.gz"; - sha256 = "sha256-k5VtkNRf+p+E+MovcYpCEF5CNtCUzgMiEYSfGhLNwVg="; + sha256 = "sha256-aW5QBSAI3k+nqx2BjVt362MkfuovBXURTJWS/5GIphQ="; }; prePatch = '' From fd39cdbfd823b2a53a6454687c73fbd41761b8aa Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Sun, 19 Jan 2025 20:26:41 -0600 Subject: [PATCH 32/58] vimPlugins.git-conflict-nvim: 2024-12-27 -> 2.1.0 Reverting back to last working version of plugin. --- pkgs/applications/editors/vim/plugins/overrides.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pkgs/applications/editors/vim/plugins/overrides.nix b/pkgs/applications/editors/vim/plugins/overrides.nix index adec08943624..b97ec9349a3b 100644 --- a/pkgs/applications/editors/vim/plugins/overrides.nix +++ b/pkgs/applications/editors/vim/plugins/overrides.nix @@ -1725,6 +1725,18 @@ in dependencies = [ self.plenary-nvim ]; }; + git-conflict-nvim = super.git-conflict-nvim.overrideAttrs { + # TODO: Remove after next fixed version + # https://github.com/akinsho/git-conflict.nvim/issues/103 + version = "2.1.0"; + src = fetchFromGitHub { + owner = "akinsho"; + repo = "git-conflict.nvim"; + tag = "v2.1.0"; + hash = "sha256-1t0kKxTGLuOvuRkoLgkoqMZpF+oKo8+gMsTdgPsSb+8="; + }; + }; + minimap-vim = super.minimap-vim.overrideAttrs { preFixup = '' substituteInPlace $out/plugin/minimap.vim \ From 7d0cbf1b6ff7d13bc33e5ff9ebd1ac9830aa6c3a Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 02:46:31 +0000 Subject: [PATCH 33/58] nwg-panel: 0.9.59 -> 0.9.61 --- pkgs/by-name/nw/nwg-panel/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/nw/nwg-panel/package.nix b/pkgs/by-name/nw/nwg-panel/package.nix index 5e64db8b9542..5031835507eb 100644 --- a/pkgs/by-name/nw/nwg-panel/package.nix +++ b/pkgs/by-name/nw/nwg-panel/package.nix @@ -23,13 +23,13 @@ python3Packages.buildPythonApplication rec { pname = "nwg-panel"; - version = "0.9.59"; + version = "0.9.61"; src = fetchFromGitHub { owner = "nwg-piotr"; repo = "nwg-panel"; tag = "v${version}"; - hash = "sha256-ey0Fb9ilm7I2QWG1gQpnHTlMPoQswNlkrZ/WhUaLbDk="; + hash = "sha256-1p6fWP4iS8yryVv0DC+yQSSJj5EeAYNdiJiklKpfqgM="; }; # No tests From a4677d48c1763423de84b92ed19c5050071fe0a0 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 02:51:18 +0000 Subject: [PATCH 34/58] simpleDBus: 0.8.1 -> 0.9.0 --- pkgs/by-name/si/simpleDBus/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/si/simpleDBus/package.nix b/pkgs/by-name/si/simpleDBus/package.nix index 97dfd36492e0..6adc64739811 100644 --- a/pkgs/by-name/si/simpleDBus/package.nix +++ b/pkgs/by-name/si/simpleDBus/package.nix @@ -10,13 +10,13 @@ stdenv.mkDerivation (finalAttrs: { pname = "simpleDBus"; - version = "0.8.1"; + version = "0.9.0"; src = fetchFromGitHub { owner = "OpenBluetoothToolbox"; repo = "SimpleBLE"; rev = "v${finalAttrs.version}"; - hash = "sha256-rtctBKHujVqZXkblgoaaOQmrHT15HiDmev+rS4ZnYqI="; + hash = "sha256-suVaiFE60g2OlIF4DLGoHKr7ehUtThLcB/GoVCOfxJg="; }; outputs = [ From 3cef4905f08361e896c6567f9ce682240277d34b Mon Sep 17 00:00:00 2001 From: Tristan Ross Date: Wed, 15 Jan 2025 22:38:30 -0800 Subject: [PATCH 35/58] cjson: fix building with clang --- pkgs/by-name/cj/cjson/package.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/by-name/cj/cjson/package.nix b/pkgs/by-name/cj/cjson/package.nix index d344e5ad45ec..7f1eac88571a 100644 --- a/pkgs/by-name/cj/cjson/package.nix +++ b/pkgs/by-name/cj/cjson/package.nix @@ -18,6 +18,10 @@ stdenv.mkDerivation rec { nativeBuildInputs = [ cmake ]; + cmakeFlags = lib.optional (stdenv.cc.isClang && !stdenv.hostPlatform.isDarwin) ( + lib.cmakeBool "ENABLE_CUSTOM_COMPILER_FLAGS" false + ); + # cJSON actually uses C99 standard, not C89 # https://github.com/DaveGamble/cJSON/issues/275 postPatch = '' From eb453754f44515407b2bc39c7c93ccda1cafcd86 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 02:53:47 +0000 Subject: [PATCH 36/58] spfft: 1.1.0 -> 1.1.1 --- pkgs/by-name/sp/spfft/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/sp/spfft/package.nix b/pkgs/by-name/sp/spfft/package.nix index 1045173353b3..bcef437f72c8 100644 --- a/pkgs/by-name/sp/spfft/package.nix +++ b/pkgs/by-name/sp/spfft/package.nix @@ -28,13 +28,13 @@ assert builtins.elem gpuBackend [ stdenv.mkDerivation rec { pname = "SpFFT"; - version = "1.1.0"; + version = "1.1.1"; src = fetchFromGitHub { owner = "eth-cscs"; repo = pname; rev = "v${version}"; - hash = "sha256-hZdB/QcjL8rjvR1YZS+CHe5U5zxedpfDq6msMih4Elc="; + hash = "sha256-Qc/omdRv7dW9NJUOczMZJKhc+Z/sXeIxv3SbpegAGdU="; }; nativeBuildInputs = [ From 95dbf5b038a13db6062e407c757818b621f9b56f Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 04:17:42 +0000 Subject: [PATCH 37/58] changedetection-io: 0.48.05 -> 0.48.06 --- pkgs/by-name/ch/changedetection-io/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/ch/changedetection-io/package.nix b/pkgs/by-name/ch/changedetection-io/package.nix index 390f4079216b..56943720cc0b 100644 --- a/pkgs/by-name/ch/changedetection-io/package.nix +++ b/pkgs/by-name/ch/changedetection-io/package.nix @@ -6,14 +6,14 @@ python3.pkgs.buildPythonApplication rec { pname = "changedetection-io"; - version = "0.48.05"; + version = "0.48.06"; format = "setuptools"; src = fetchFromGitHub { owner = "dgtlmoon"; repo = "changedetection.io"; tag = version; - hash = "sha256-oOuHPOvs3qcQcibKyChe2AK1OB3JK/xRKUp1cj5p5PU="; + hash = "sha256-6ofCVmdO8Z/EyJjbzAQdwnqUfsjtPzveNd5Zfj3pcFM="; }; pythonRelaxDeps = true; From e6305a33bf221476ad898a28e44cb9704cab51f1 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 04:39:10 +0000 Subject: [PATCH 38/58] v2rayn: 7.6.2 -> 7.7.0 --- pkgs/by-name/v2/v2rayn/deps.json | 18 ++++-------------- pkgs/by-name/v2/v2rayn/package.nix | 4 ++-- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/pkgs/by-name/v2/v2rayn/deps.json b/pkgs/by-name/v2/v2rayn/deps.json index 5f222d833fad..847a4f37d9ec 100644 --- a/pkgs/by-name/v2/v2rayn/deps.json +++ b/pkgs/by-name/v2/v2rayn/deps.json @@ -81,8 +81,8 @@ }, { "pname": "CliWrap", - "version": "3.7.0", - "hash": "sha256-hXClLGuhscCrcBaymrp57Prh4m8Qe0vdE4S2ErIM13w=" + "version": "3.7.1", + "hash": "sha256-e0snh/9Ai6/Gw5ycQox2H5nGrPhKfT2sH9dQNjbrrCI=" }, { "pname": "DialogHost.Avalonia", @@ -91,8 +91,8 @@ }, { "pname": "Downloader", - "version": "3.3.1", - "hash": "sha256-vJRRKgA+pUr5/kWBTu7oMy+pat+jKL9SD/G7CmV0WLk=" + "version": "3.3.3", + "hash": "sha256-H8HJKL71qC+nHVmuhhPDEHy434/NXJNqPeitJOe856k=" }, { "pname": "DynamicData", @@ -284,11 +284,6 @@ "version": "2.1.2", "hash": "sha256-e56+FgxEHqV3SGQx0ZAqzlscPxNUPXJ8Ls9rtqET1S4=" }, - { - "pname": "System.CodeDom", - "version": "9.0.0", - "hash": "sha256-578lcBgswW0eM16r0EnJzfGodPx86RxxFoZHc2PSzsw=" - }, { "pname": "System.Collections.Immutable", "version": "8.0.0", @@ -309,11 +304,6 @@ "version": "8.0.0", "hash": "sha256-LdpB1s4vQzsOODaxiKstLks57X9DTD5D6cPx8DE1wwE=" }, - { - "pname": "System.Management", - "version": "9.0.0", - "hash": "sha256-UyLO5dgNVC7rBT1S6o/Ix6EQGlVTSWUQtVC+/cyTkfQ=" - }, { "pname": "System.Memory", "version": "4.5.3", diff --git a/pkgs/by-name/v2/v2rayn/package.nix b/pkgs/by-name/v2/v2rayn/package.nix index 73969743821d..3391c8a1504c 100644 --- a/pkgs/by-name/v2/v2rayn/package.nix +++ b/pkgs/by-name/v2/v2rayn/package.nix @@ -19,13 +19,13 @@ }: buildDotnetModule rec { pname = "v2rayn"; - version = "7.6.2"; + version = "7.7.0"; src = fetchFromGitHub { owner = "2dust"; repo = "v2rayN"; tag = version; - hash = "sha256-o+aeBdV/OT4cFovCeivM2i60r4mbZ0FPOY8XNdKRrpg="; + hash = "sha256-gnGZtHSmmyxTf+/Dp1cEXI1odI8SiFLzATd9PNnAC7E="; }; projectFile = "v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj"; From a64584d9c022fe8baa83a216ae2d7e470009e412 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 04:50:51 +0000 Subject: [PATCH 39/58] ytdl-sub: 2025.01.15 -> 2025.01.17 --- pkgs/by-name/yt/ytdl-sub/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/yt/ytdl-sub/package.nix b/pkgs/by-name/yt/ytdl-sub/package.nix index 1bc1c30ae0c5..05c35224b26c 100644 --- a/pkgs/by-name/yt/ytdl-sub/package.nix +++ b/pkgs/by-name/yt/ytdl-sub/package.nix @@ -8,14 +8,14 @@ }: python3Packages.buildPythonApplication rec { pname = "ytdl-sub"; - version = "2025.01.15"; + version = "2025.01.17"; pyproject = true; src = fetchFromGitHub { owner = "jmbannon"; repo = "ytdl-sub"; tag = version; - hash = "sha256-UjCs71nXi77yvB9BhYxT+2G9I+qHEB5Jnhe+GJuppdY="; + hash = "sha256-6RazXOXkBXwhJz8eNhrLIoEAVXnFEAF3O+SDKSjAlYo="; }; postPatch = '' From b25086345bbcd124e9de4693a47fed5a44c8fbe4 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 04:52:22 +0000 Subject: [PATCH 40/58] clouddrive2: 0.8.5 -> 0.8.6 --- pkgs/by-name/cl/clouddrive2/package.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkgs/by-name/cl/clouddrive2/package.nix b/pkgs/by-name/cl/clouddrive2/package.nix index a42d9906a4d2..fdb21c2c94ec 100644 --- a/pkgs/by-name/cl/clouddrive2/package.nix +++ b/pkgs/by-name/cl/clouddrive2/package.nix @@ -11,16 +11,16 @@ let in stdenv.mkDerivation (finalAttrs: { pname = "clouddrive2"; - version = "0.8.5"; + version = "0.8.6"; src = fetchurl { url = "https://github.com/cloud-fs/cloud-fs.github.io/releases/download/v${finalAttrs.version}/clouddrive-2-${os}-${arch}-${finalAttrs.version}.tgz"; hash = { - x86_64-linux = "sha256-6zdP0d5XyBYG7+SGqb2DSaD6rJrBn8OjGr9BXfP1Ctc="; - aarch64-linux = "sha256-7u/AKZGL/AkUsakZexC/oxgjoayaxH7OiRE+xnH+Gus="; - x86_64-darwin = "sha256-/uDxZVlULl3PnuAaF7kWAyukaQoF7DV8m5gowTFdMEQ="; - aarch64-darwin = "sha256-xZ60pi2JYSLDLaR0Qe/fyEhzyu17U2fbDp1lo2qViIs="; + x86_64-linux = "sha256-79P356HchNTpiFd7V/XeOuFyS7xpS/SARyS7X7a3Ko4="; + aarch64-linux = "sha256-GXjr4RZCRE+oz+ldpJ4lgN5LxPD/BU1544ApNqULHTc="; + x86_64-darwin = "sha256-otkVfPTRYmdw818RESavkZh0PRpFyrum56TnNTol538="; + aarch64-darwin = "sha256-hePGS4CJibSTqav5Gk2/U27SO1JAeReCSDpCaijCa74="; } .${stdenv.hostPlatform.system} or (throw "unsupported system ${stdenv.hostPlatform.system}"); }; From d7356a72a6ecb1bca16317402854c698e0a14ad5 Mon Sep 17 00:00:00 2001 From: K900 Date: Mon, 20 Jan 2025 09:14:29 +0300 Subject: [PATCH 41/58] linux_6_13: init --- pkgs/os-specific/linux/kernel/kernels-org.json | 4 ++++ pkgs/top-level/aliases.nix | 2 ++ pkgs/top-level/linux-kernels.nix | 11 ++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pkgs/os-specific/linux/kernel/kernels-org.json b/pkgs/os-specific/linux/kernel/kernels-org.json index 8f7975b4746d..3c7665c5b5ab 100644 --- a/pkgs/os-specific/linux/kernel/kernels-org.json +++ b/pkgs/os-specific/linux/kernel/kernels-org.json @@ -30,5 +30,9 @@ "6.12": { "version": "6.12.10", "hash": "sha256:15xjjn8ff7g9q0ljr2g8k098ppxnpvxlgv22rdrplls8sxg6wlaa" + }, + "6.13": { + "version": "6.13", + "hash": "sha256:0vhdz1as27kxav81rkf6fm85sqrbj5hjhz5hpyxcd5b6p1pcr7g7" } } diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix index 08a598b64105..e3dfdfb89649 100644 --- a/pkgs/top-level/aliases.nix +++ b/pkgs/top-level/aliases.nix @@ -744,6 +744,7 @@ mapAliases { linuxPackages_6_10 = linuxKernel.packages.linux_6_10; linuxPackages_6_11 = linuxKernel.packages.linux_6_11; linuxPackages_6_12 = linuxKernel.packages.linux_6_12; + linuxPackages_6_13 = linuxKernel.packages.linux_6_13; linuxPackages_rpi0 = linuxKernel.packages.linux_rpi1; linuxPackages_rpi02w = linuxKernel.packages.linux_rpi3; linuxPackages_rpi1 = linuxKernel.packages.linux_rpi1; @@ -769,6 +770,7 @@ mapAliases { linux_6_10 = linuxKernel.kernels.linux_6_10; linux_6_11 = linuxKernel.kernels.linux_6_11; linux_6_12 = linuxKernel.kernels.linux_6_12; + linux_6_13 = linuxKernel.kernels.linux_6_13; linux_rpi0 = linuxKernel.kernels.linux_rpi1; linux_rpi02w = linuxKernel.kernels.linux_rpi3; linux_rpi1 = linuxKernel.kernels.linux_rpi1; diff --git a/pkgs/top-level/linux-kernels.nix b/pkgs/top-level/linux-kernels.nix index 7939e8df371c..83e765938c93 100644 --- a/pkgs/top-level/linux-kernels.nix +++ b/pkgs/top-level/linux-kernels.nix @@ -197,6 +197,14 @@ in { ]; }; + linux_6_13 = callPackage ../os-specific/linux/kernel/mainline.nix { + branch = "6.13"; + kernelPatches = [ + kernelPatches.bridge_stp_helper + kernelPatches.request_key_helper + ]; + }; + linux_testing = let testing = callPackage ../os-specific/linux/kernel/mainline.nix { # A special branch that tracks the kernel under the release process @@ -645,6 +653,7 @@ in { linux_6_6 = recurseIntoAttrs (packagesFor kernels.linux_6_6); linux_6_11 = recurseIntoAttrs (packagesFor kernels.linux_6_11); linux_6_12 = recurseIntoAttrs (packagesFor kernels.linux_6_12); + linux_6_13 = recurseIntoAttrs (packagesFor kernels.linux_6_13); } // lib.optionalAttrs config.allowAliases { linux_4_14 = throw "linux 4.14 was removed because it will reach its end of life within 23.11"; # Added 2023-10-11 linux_4_19 = throw "linux 4.19 was removed because it will reach its end of life within 24.11"; # Added 2024-09-21 @@ -711,7 +720,7 @@ in { packageAliases = { linux_default = packages.linux_6_6; # Update this when adding the newest kernel major version! - linux_latest = packages.linux_6_12; + linux_latest = packages.linux_6_13; linux_rt_default = packages.linux_rt_5_15; linux_rt_latest = packages.linux_rt_6_6; } // lib.optionalAttrs config.allowAliases { From e4d3693cd8784f4eccee167a6d2722cec2c1f519 Mon Sep 17 00:00:00 2001 From: K900 Date: Mon, 20 Jan 2025 09:39:28 +0300 Subject: [PATCH 42/58] perf: don't apply dmesg patch on 6.13, remove 6.10 patches --- .../os-specific/linux/kernel/perf/default.nix | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/pkgs/os-specific/linux/kernel/perf/default.nix b/pkgs/os-specific/linux/kernel/perf/default.nix index b947a2650f2d..c74aa7f4285a 100644 --- a/pkgs/os-specific/linux/kernel/perf/default.nix +++ b/pkgs/os-specific/linux/kernel/perf/default.nix @@ -61,24 +61,11 @@ stdenv.mkDerivation { inherit (kernel) version src; patches = - lib.optionals (lib.versionAtLeast kernel.version "5.10") [ - # fix wrong path to dmesg - ./fix-dmesg-path.diff - ] - ++ lib.optionals (lib.versions.majorMinor kernel.version == "6.10") [ - (fetchpatch { - url = "https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/patch/?id=0f0e1f44569061e3dc590cd0b8cb74d8fd53706b"; - hash = "sha256-9u/zhbsDgwOr4T4k9td/WJYRuSHIfbtfS+oNx8nbOlM="; - }) - (fetchpatch { - url = "https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/patch/?id=366e17409f1f17ad872259ce4a4f8a92beb4c4ee"; - hash = "sha256-NZK1u40qvMwWcgkgJPGpEax2eMo9xHrCQxSYYOK0rbo="; - }) - (fetchpatch { - url = "https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/patch/?id=1d302f626c2a23e4fd05bb810eff300e8f2174fd"; - hash = "sha256-KhCmof8LkyTcBBpfMEtolL3m3kmC5rukKzQvufVKCdI="; - }) - ]; + lib.optionals (lib.versionAtLeast kernel.version "5.10" && lib.versionOlder kernel.version "6.13") + [ + # fix wrong path to dmesg + ./fix-dmesg-path.diff + ]; postPatch = '' From 6a580ab6705f535dc83982f84eeb35413dec4f0b Mon Sep 17 00:00:00 2001 From: K900 Date: Mon, 20 Jan 2025 09:59:48 +0300 Subject: [PATCH 43/58] nixos/release-small: add latestKernel test --- nixos/release-small.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nixos/release-small.nix b/nixos/release-small.nix index d2dc59b8ebab..27857b0cdfd2 100644 --- a/nixos/release-small.nix +++ b/nixos/release-small.nix @@ -64,6 +64,11 @@ rec { proxy simple ; + latestKernel = { + inherit (nixos'.tests.latestKernel) + login + ; + }; installer = { inherit (nixos'.tests.installer) lvm @@ -137,6 +142,7 @@ rec { "nixos.tests.ipv6" "nixos.tests.installer.simpleUefiSystemdBoot" "nixos.tests.login" + "nixos.tests.latestKernel.login" "nixos.tests.misc" "nixos.tests.nat.firewall" "nixos.tests.nat.standalone" From 800938116f9ceecb921fec4d700e5ef5577521ca Mon Sep 17 00:00:00 2001 From: Morgan Jones Date: Fri, 8 Nov 2024 21:43:05 -0800 Subject: [PATCH 44/58] mattermost: enable test suite, mmctl support, and plugin building Add the following passthrus: - mattermost.withTests (builds with tests but takes a while) - mattermost.withoutTests (builds without tests but is shorter) - mattermost.tests.mattermostWithTests - mattermost.buildPlugin (builds a plugin from source) Enable the mmctl build, and its tests, if selected. --- pkgs/by-name/ma/mattermost/build-plugin.nix | 153 ++++++++ pkgs/by-name/ma/mattermost/package.nix | 170 ++++++--- pkgs/by-name/ma/mattermost/tests.nix | 399 ++++++++++++++++++++ 3 files changed, 670 insertions(+), 52 deletions(-) create mode 100644 pkgs/by-name/ma/mattermost/build-plugin.nix create mode 100644 pkgs/by-name/ma/mattermost/tests.nix diff --git a/pkgs/by-name/ma/mattermost/build-plugin.nix b/pkgs/by-name/ma/mattermost/build-plugin.nix new file mode 100644 index 000000000000..8dd89211e2e2 --- /dev/null +++ b/pkgs/by-name/ma/mattermost/build-plugin.nix @@ -0,0 +1,153 @@ +{ + lib, + stdenv, + mattermost, + nodejs, + writeShellScriptBin, + buildGoModule, + golangci-lint, + gotestsum, + fetchNpmDeps, + npmHooks, + npm-lockfile-fix, +}: + +{ + # The name of the plugin. + pname, + # The plugin version. + version, + # The plugin source. + src, + + # True to ignore golangci-lint warnings. By default set to true + # since plugins warn about the Mattermost interface but build fine. + ignoreGoLintWarnings ? true, + + # The hash of the gomod vendor directory. + vendorHash ? lib.fakeHash, + + # True to build the webapp. + buildWebapp ? true, + + # The NPM dependency hash. + npmDepsHash ? lib.fakeHash, + + # Any extra attributes to pass to buildGoModule. + extraGoModuleAttrs ? { }, +}: + +let + fakeGit = writeShellScriptBin "git" '' + case "$1" in + rev-parse|describe|tag) + echo ${lib.escapeShellArg version} ;; + config) + echo ${lib.escapeShellArg pname} ;; + *) ;; + esac + ''; + + fake-golangci-lint = writeShellScriptBin "golangci-lint" '' + set -uo pipefail + ${lib.getExe golangci-lint} "$@" + result=$? + echo "golangci-lint returned: $result" >&2 + ${lib.optionalString (ignoreGoLintWarnings) '' + if [ $result != 0 ]; then + cat <&2 + Ignoring return value since ignoreGoLintWarnings was true. + Tell this plugin author to fix their lint. + EOF + result=0 + fi + ''} + exit $result + ''; +in +buildGoModule ( + rec { + name = "${pname}-${version}.tar.gz"; + inherit version src vendorHash; + + npmDeps = + if buildWebapp then + fetchNpmDeps { + src = "${src}/webapp"; + hash = npmDepsHash; + forceGitDeps = true; + postFetch = '' + ${lib.getExe npm-lockfile-fix} package-lock.json + ''; + } + else + null; + + makeCacheWritable = true; + forceGitDeps = true; + + overrideModAttrs = final: { + preBuild = '' + go mod tidy + ''; + + # Adding the NPM config hook here breaks things, and isn't even needed. + nativeBuildInputs = lib.lists.remove npmHooks.npmConfigHook final.nativeBuildInputs; + }; + + prePatch = lib.optionalString buildWebapp '' + # Move important node.js files up a level and symlink the originals so the setup hook finds them + for file in package.json package-lock.json node_modules; do + if [ -f "webapp/$file" ]; then + mv "webapp/$file" . + fi + (cd webapp && ln -vsf "../$file") + done + + # Don't allow Go installation in the sandbox, but also don't fail + substituteInPlace Makefile --replace-warn '$(GO) install' '@echo $(GO) install' + ''; + + nativeBuildInputs = [ + fakeGit + nodejs + npmHooks.npmConfigHook + ]; + + buildInputs = [ mattermost ]; + + preBuild = '' + # Or else Babel doesn't run. + export NODE_OPTIONS=--openssl-legacy-provider + + # Only build GOOS and GOARCH plugins so we aren't + # spitting out FreeBSD/Windows/Darwin executables we don't use. + export MM_SERVICESETTINGS_ENABLEDEVELOPER=true + ''; + + buildPhase = '' + runHook preBuild + + # These dependencies are ordinarily fetched via the Makefile, making + # $(GO) install only echo means we still need to install them. + mkdir -p bin + ln -sf ${lib.getExe fake-golangci-lint} bin/golangci-lint + ln -sf ${lib.getExe gotestsum} bin/gotestsum + + # Do the build. + make + + runHook postBuild + ''; + + installPhase = '' + plugin="$(ls dist/*.tar.gz | tail -n1)" + if [ -z "$plugin" ] || [ ! -f "$plugin" ]; then + echo "No plugin tarball in dist folder!" >&2 + exit 1 + fi + cp -av "$plugin" $out + ''; + } + // extraGoModuleAttrs +) diff --git a/pkgs/by-name/ma/mattermost/package.nix b/pkgs/by-name/ma/mattermost/package.nix index 54559408399b..55d2cc7c6488 100644 --- a/pkgs/by-name/ma/mattermost/package.nix +++ b/pkgs/by-name/ma/mattermost/package.nix @@ -1,5 +1,7 @@ { lib, + callPackage, + stdenvNoCC, buildGoModule, fetchFromGitHub, buildNpmPackage, @@ -24,7 +26,60 @@ }, }: -buildGoModule rec { +let + /* + Helper function that sets the `withTests` and `withoutTests` passthru correctly, + and returns the version with tests. + + The primary reason to use this helper over reindenting the whole file is to avoid + lots of manual backporting when the update script runs. + */ + buildMattermost = + { passthru, ... }@args: + let + # Joins the webapp and Matermost derivation together. + # That way patches to the webapp won't cause a rebuild of the server. + wrapMattermost = + server: + stdenvNoCC.mkDerivation { + pname = "${server.pname}-wrapped"; + inherit (server) version; + inherit server; + inherit (server) webapp; + + dontUnpack = true; + + # Just link all the server and webapp root directories together. + installPhase = '' + mkdir -p $out + for dir in "$server" "$webapp"; do + for path in "$dir"/*; do + ln -s "$path" "$out/$(basename -- "$path")" + done + done + ''; + + passthru = finalPassthru // { + inherit server; + inherit (server) webapp; + }; + + inherit (server) meta; + }; + finalPassthru = + let + withoutTestsUnwrapped = buildGoModule (args // { passthru = finalPassthru; }); + withTestsUnwrapped = callPackage ./tests.nix { mattermost = withoutTestsUnwrapped; }; + in + lib.recursiveUpdate passthru rec { + withoutTests = wrapMattermost withoutTestsUnwrapped; + withTests = wrapMattermost withTestsUnwrapped; + tests.mattermostWithTests = withTests; + }; + in + finalPassthru.withTests; +in +buildMattermost rec { pname = "mattermost"; inherit (versionInfo) version; @@ -64,14 +119,12 @@ buildGoModule rec { # We use go 1.22's workspace vendor command, which is not yet available # in the default version of go used in nixpkgs, nor is it used by upstream: # https://github.com/mattermost/mattermost/issues/26221#issuecomment-1945351597 - overrideModAttrs = ( - _: { - buildPhase = '' - make setup-go-work - go work vendor -e - ''; - } - ); + overrideModAttrs = _: { + buildPhase = '' + make setup-go-work + go work vendor -e -v + ''; + }; npmDeps = fetchNpmDeps { inherit src; @@ -81,46 +134,6 @@ buildGoModule rec { forceGitDeps = true; }; - webapp = buildNpmPackage rec { - pname = "mattermost-webapp"; - inherit version src; - - sourceRoot = "${src.name}/webapp"; - - # Remove deprecated image-webpack-loader causing build failures - # See: https://github.com/tcoopman/image-webpack-loader#deprecated - postPatch = '' - substituteInPlace channels/webpack.config.js \ - --replace-fail 'options: {}' 'options: { disable: true }' - ''; - - npmDepsHash = npmDeps.hash; - makeCacheWritable = true; - forceGitDeps = true; - - npmRebuildFlags = [ "--ignore-scripts" ]; - - buildPhase = '' - runHook preBuild - - npm run build --workspace=platform/types - npm run build --workspace=platform/client - npm run build --workspace=platform/components - npm run build --workspace=channels - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - mkdir -p $out - cp -a channels/dist/* $out - - runHook postInstall - ''; - }; - inherit (versionInfo) vendorHash; modRoot = "./server"; @@ -128,7 +141,10 @@ buildGoModule rec { make setup-go-work ''; - subPackages = [ "cmd/mattermost" ]; + subPackages = [ + "cmd/mattermost" + "cmd/mmctl" + ]; tags = [ "production" ]; @@ -147,8 +163,7 @@ buildGoModule rec { shopt -s extglob mkdir -p $out/{i18n,fonts,templates,config} - # Link in the client and copy the language packs. - ln -sf $webapp $out/client + # Copy the language packs. cp -a $src/server/i18n/* $out/i18n/ # Fonts have the execute bit set, remove it. @@ -162,6 +177,13 @@ buildGoModule rec { go run -tags production ./scripts/config_generator ''; + doInstallCheck = true; + installCheckPhase = '' + for subPackage in $subPackages; do + "$out/bin/$(basename -- "$subPackage")" version | grep "$version" + done + ''; + passthru = { updateScript = nix-update-script { extraArgs = @@ -175,6 +197,50 @@ buildGoModule rec { ]; }; tests.mattermost = nixosTests.mattermost; + + # Builds a Mattermost plugin. + buildPlugin = callPackage ./build-plugin.nix { }; + + # Builds the webapp. + webapp = buildNpmPackage rec { + pname = "mattermost-webapp"; + inherit version src; + + sourceRoot = "${src.name}/webapp"; + + # Remove deprecated image-webpack-loader causing build failures + # See: https://github.com/tcoopman/image-webpack-loader#deprecated + postPatch = '' + substituteInPlace channels/webpack.config.js \ + --replace-fail 'options: {}' 'options: { disable: true }' + ''; + + npmDepsHash = npmDeps.hash; + makeCacheWritable = true; + forceGitDeps = true; + + npmRebuildFlags = [ "--ignore-scripts" ]; + + buildPhase = '' + runHook preBuild + + npm run build --workspace=platform/types + npm run build --workspace=platform/client + npm run build --workspace=platform/components + npm run build --workspace=channels + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/client + cp -a channels/dist/* $out/client + + runHook postInstall + ''; + }; }; meta = with lib; { diff --git a/pkgs/by-name/ma/mattermost/tests.nix b/pkgs/by-name/ma/mattermost/tests.nix new file mode 100644 index 000000000000..3e70be5e5ade --- /dev/null +++ b/pkgs/by-name/ma/mattermost/tests.nix @@ -0,0 +1,399 @@ +{ + lib, + stdenv, + mattermost, + gotestsum, + which, + postgresql, + mariadb, + redis, + curl, + nettools, + runtimeShell, +}: + +let + inherit (lib.lists) optionals; + inherit (lib.strings) versionAtLeast; + is10 = version: versionAtLeast version "10.0"; +in +mattermost.overrideAttrs ( + final: prev: { + doCheck = true; + checkTargets = [ + "test-server" + "test-mmctl" + ]; + nativeCheckInputs = [ + which + postgresql + mariadb + redis + curl + nettools + gotestsum + ]; + + postPatch = + prev.postPatch or "" + + '' + # Just echo install/get/mod commands in the Makefile, since the dependencies are locked. + substituteInPlace server/Makefile \ + --replace-warn '$(GO) install' '@echo $(GO) install' \ + --replace-warn '$(GO) get' '@echo $(GO) get' \ + --replace-warn '$(GO) get' '@echo $(GO) mod' + # mmctl tests shell out by writing a bash script to a tempfile + substituteInPlace server/cmd/mmctl/commands/config_e2e_test.go \ + --replace-fail '#!/bin/bash' '#!${runtimeShell}' + ''; + + # Make sure we disable tests that are broken. + # Use: `nix log | grep FAIL: | awk '{print $3}' | sort` + # and then try to pick the most specific test set to disable, such as: + # X TestFoo + # X TestFoo/TestBar + # -> TestFoo/TestBar/baz_test + disabledTests = + [ + # All these plugin tests for mmctl reach out to the marketplace, which is impossible in the sandbox + "TestMmctlE2ESuite/TestPluginDeleteCmd/Delete_Plugin/SystemAdminClient" + "TestMmctlE2ESuite/TestPluginDeleteCmd/Delete_Plugin/LocalClient" + "TestMmctlE2ESuite/TestPluginDeleteCmd/Delete_a_Plugin_without_permissions" + "TestMmctlE2ESuite/TestPluginDeleteCmd/Delete_Unknown_Plugin/SystemAdminClient" + "TestMmctlE2ESuite/TestPluginDeleteCmd/Delete_Unknown_Plugin/LocalClient" + "TestMmctlE2ESuite/TestPluginInstallURLCmd/install_new_plugins/SystemAdminClient" + "TestMmctlE2ESuite/TestPluginInstallURLCmd/install_new_plugins/LocalClient" + "TestMmctlE2ESuite/TestPluginInstallURLCmd/install_an_already_installed_plugin_without_force/SystemAdminClient" + "TestMmctlE2ESuite/TestPluginInstallURLCmd/install_an_already_installed_plugin_without_force/LocalClient" + "TestMmctlE2ESuite/TestPluginInstallURLCmd/install_an_already_installed_plugin_with_force/SystemAdminClient" + "TestMmctlE2ESuite/TestPluginInstallURLCmd/install_an_already_installed_plugin_with_force/LocalClient" + "TestMmctlE2ESuite/TestPluginMarketplaceInstallCmd/install_a_plugin/SystemAdminClient" + "TestMmctlE2ESuite/TestPluginMarketplaceInstallCmd/install_a_plugin/LocalClient" + "TestMmctlE2ESuite/TestPluginMarketplaceListCmd/List_Marketplace_Plugins_for_Admin_User/SystemAdminClient" + "TestMmctlE2ESuite/TestPluginMarketplaceListCmd/List_Marketplace_Plugins_for_Admin_User/LocalClient" + + # Seems to just be broken. + "TestMmctlE2ESuite/TestPreferenceUpdateCmd" + + # Has a hardcoded "google.com" test which also verifies that the address isn't loopback, + # so we also can't just substituteInPlace to one that will resolve + "TestDialContextFilter" + + # No interfaces but loopback in the sandbox, so returns empty + "TestGetServerIPAddress" + + # S3 bucket tests (needs Minio) + "TestInsecureMakeBucket" + "TestMakeBucket" + "TestListDirectory" + "TestTimeout" + "TestStartServerNoS3Bucket" + "TestS3TestConnection" + "TestS3FileBackendTestSuite" + "TestS3FileBackendTestSuiteWithEncryption" + + # Mail tests (needs a SMTP server) + "TestSendMailUsingConfig" + "TestSendMailUsingConfigAdvanced" + "TestSendMailWithEmbeddedFilesUsingConfig" + "TestSendCloudWelcomeEmail" + "TestMailConnectionAdvanced" + "TestMailConnectionFromConfig" + "TestEmailTest" + "TestBasicAPIPlugins/test_send_mail_plugin" + + # Seems to be unreliable + "TestPluginAPIUpdateUserPreferences" + "TestPluginAPIGetUserPreferences" + + # These invite tests try to send a welcome email and we don't have a SMTP server up. + "TestInviteUsersToTeam" + "TestInviteGuestsToTeam" + "TestSendInviteEmails" + "TestDeliver" + + # https://github.com/mattermost/mattermost/issues/29184 + "TestUpAndDownMigrations/Should_be_reversible_for_mysql" + ] + ++ optionals (is10 final.version) [ + ## mattermostLatest test ignores + + # These bot related tests appear to be broken. + "TestCreateBot" + "TestPatchBot" + "TestGetBot" + "TestEnableBot" + "TestDisableBot" + "TestAssignBot" + "TestConvertBotToUser" + + # Need Elasticsearch or Opensearch + "TestBlevePurgeIndexes" + "TestOpensearchAggregation" + "TestOpensearchInterfaceTestSuite" + "TestOpenSearchIndexerJobIsEnabled" + "TestOpenSearchIndexerPending" + "TestBulkProcessor" + "TestElasticsearchAggregation" + "TestElasticsearchInterfaceTestSuite" + "TestElasticSearchIndexerJobIsEnabled" + "TestElasticSearchIndexerPending" + + # Appear to be broken. + "TestSessionStore/MySQL/SessionGetWithDeviceId" + "TestSessionStore/MySQL/GetMobileSessionMetadata" + ] + ++ optionals (!stdenv.isx86_64) [ + # aarch64: invalid operating system or processor architecture + "TestCanIUpgradeToE0" + ]; + + preCheck = '' + cleanup() { + runHook postCheck + } + trap cleanup EXIT + + # Runs an iteration of the wait loop. + # Returns 0 if we should retry, 1 otherwise. + _wait_loop() { + local process="$1" + local direction="$2" + echo "Waiting for $process to go $direction ($_TRIES attempt(s) left)..." >&2 + _TRIES=$((_TRIES-1)) + if [ $_TRIES -le 0 ]; then + return 1 + else + sleep 1 + return 0 + fi + } + + # Waits on a command named '$1' with direction '$2'. + # The rest of the command is specified in $@. + # If the direction is up, waits for the command to succeed at 1 second intervals. + # If it's down, waits for the command to fail at 1 second intervals. + # Uses a maximum of 5 iterations. Returns 0 if all was ok, or 1 if we timed out. + wait_cmd() { + local process="$1" + local direction="$2" + local tries=10 + _TRIES=$tries + shift; shift + if [ "$direction" == "up" ]; then + while ! "$@" &>/dev/null; do + if ! _wait_loop "$process" "$direction"; then + break + fi + done + else + while "$@" &>/dev/null; do + if ! _wait_loop "$process" "$direction"; then + break + fi + done + fi + + if [ $_TRIES -le 0 ]; then + echo "Timed out after $tries tries" >&2 + return 1 + else + echo "OK, $process went $direction." >&2 + return 0 + fi + } + + # Waits for MySQL to come up or down. + wait_mysql() { + wait_cmd mysql "$1" mysqladmin ping + } + + # Waits for Postgres to come up or down. + wait_postgres() { + wait_cmd postgres "$1" pg_isready -h localhost + } + + # Waits for Redis to come up or down. + wait_redis() { + wait_cmd redis "$1" redis-cli ping + } + + # Starts MySQL. + start_mysql() { + echo "Starting MySQL at $MYSQL_HOME" >&2 + mysqld & + mysql_pid=$! + echo "... PID $mysql_pid" >&2 + wait_mysql up + } + + # Stops MySQL. + stop_mysql() { + if [ "$mysql_pid" -gt 0 ]; then + echo "Terminating MySQL at $MYSQL_HOME (PID $mysql_pid)" >&2 + mysqladmin --host=127.0.0.1 --user=root --password=mostest --wait-for-all-slaves --shutdown-timeout=30 shutdown + wait_mysql down + wait_cmd 'mysql pid' down kill -0 "$mysql_pid" + + # Make sure the worker PID went down too (but it may be already gone). + local worker_pid="$(<"$MYSQL_HOME"/mysqld.pid || echo 0)" + if [ -n "$worker_pid" ] && [ $worker_pid -gt 0 ]; then + wait_cmd 'mysql workers' down kill -0 "$worker_pid" + fi + + mysql_pid=0 + fi + } + + # Starts Postgres. + start_postgres() { + echo "Starting Postgres at $PGDATA" >&2 + pg_ctl start + wait_postgres up + } + + # Stops Postgres. + stop_postgres() { + echo "Terminating Postgres at $PGDATA" >&2 + pg_ctl stop + wait_postgres down + } + + # Starts redis. + start_redis() { + echo "Starting Redis" >&2 + (cd "$REDIS_HOME" && exec redis-server ./redis.conf) & + redis_pid=$! + echo "... PID $redis_pid" >&2 + wait_redis up + } + + # Stops redis. + stop_redis() { + echo "Stopping Redis" >&2 + kill -TERM "$redis_pid" >&2 + wait_redis down + redis_pid=0 + } + + # Configure MySQL. + export MYSQL_HOME="$NIX_BUILD_TOP/.mysql" + mkdir -p "$MYSQL_HOME" + cat <"$MYSQL_HOME/my.cnf" + [client] + port = 3306 + default-character-set = utf8mb4 + socket = $MYSQL_HOME/mysqld.sock + + [mysqld] + skip-host-cache + skip-name-resolve + basedir = ${mariadb} + datadir = $MYSQL_HOME/ + pid-file = $MYSQL_HOME/mysqld.pid + socket = $MYSQL_HOME/mysqld.sock + port = 3306 + explicit_defaults_for_timestamp + collation-server = utf8mb4_general_ci + init-connect = 'SET NAMES utf8mb4' + character-set-server = utf8mb4 + EOF + + # Start MySQL. + mysql_install_db --skip-name-resolve --auth-root-authentication-method=normal + start_mysql + + # Init MySQL. + cat <> "$PGDATA/postgresql.conf" + unix_socket_directories = '$PGDATA/run' + max_connections = 256 + shared_buffers = 96MB + EOF + start_postgres + + # Init Postgres. + cat < "$REDIS_HOME/redis.conf" + bind 127.0.0.1 + port 6379 + protected-mode no + EOF + + # Start Redis. + start_redis + + # Use gotestsum from nixpkgs instead of installing it ourselves. + mkdir -p bin + ln -s "$(which gotestsum)" bin/gotestsum + ''; + + checkPhase = '' + runHook preCheck + + # Ensure we parallelize the tests, and skip the correct ones. + # Spaces are important here due to how the Makefile works. + export GOFLAGS=" -parallel=$NIX_BUILD_CORES -skip='$(echo "$disabledTests" | tr ' ' '|')' " + + # ce n'est pas un conteneur + MMCTL_TESTFLAGS="$GOFLAGS" MM_NO_DOCKER=true make $checkTargets + + runHook postCheck + ''; + + postCheck = '' + # Clean up MySQL. + if [ -d "$MYSQL_HOME" ]; then + stop_mysql + rm -rf "$MYSQL_HOME" + fi + + # Clean up Postgres. + if [ -d "$PGDATA" ]; then + stop_postgres + rm -rf "$PGDATA" + fi + + # Clean up Redis. + if [ -d "$REDIS_HOME" ]; then + stop_redis + rm -rf "$REDIS_HOME" + fi + + # Delete the gotestsum link. + rm -f bin/gotestsum + ''; + } +) From 8944a4259cb5d8c54c81408527f600e3ff44c15e Mon Sep 17 00:00:00 2001 From: Morgan Jones Date: Sat, 16 Nov 2024 21:11:32 -0800 Subject: [PATCH 45/58] mmctl: use correct Mattermost derivation We don't have to run the full Mattermost/mmctl e2e test suite for this derivation. --- pkgs/by-name/mm/mmctl/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/by-name/mm/mmctl/package.nix b/pkgs/by-name/mm/mmctl/package.nix index f5e6c29916f6..555f8e99f573 100644 --- a/pkgs/by-name/mm/mmctl/package.nix +++ b/pkgs/by-name/mm/mmctl/package.nix @@ -2,7 +2,7 @@ mattermost, }: -mattermost.overrideAttrs (o: { +mattermost.withoutTests.server.overrideAttrs (o: { pname = "mmctl"; subPackages = [ "cmd/mmctl" ]; From f8eac009eed839d2d71f991f9c0df2e28da95a3d Mon Sep 17 00:00:00 2001 From: Morgan Jones Date: Mon, 21 Oct 2024 23:05:06 -0700 Subject: [PATCH 46/58] nixos/mattermost: modernize, support MySQL and mmctl Based on #198040. Prioritizes backwards compatibility, including database and plugin compatibility, while adding more sensible defaults like database peer authentication. Expand the scope of tests to include plugins (including building from source) and testing that a piece of media uploads and downloads to make sure the storage directory doesn't vanish. --- .../modules/services/web-apps/mattermost.nix | 863 ++++++++++++++---- nixos/tests/all-tests.nix | 2 +- nixos/tests/mattermost.nix | 169 ---- nixos/tests/mattermost/default.nix | 537 +++++++++++ nixos/tests/mattermost/test.jpg | Bin 0 -> 121879 bytes 5 files changed, 1248 insertions(+), 323 deletions(-) delete mode 100644 nixos/tests/mattermost.nix create mode 100644 nixos/tests/mattermost/default.nix create mode 100644 nixos/tests/mattermost/test.jpg diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix index 4f12774327f2..9b420f8a51fc 100644 --- a/nixos/modules/services/web-apps/mattermost.nix +++ b/nixos/modules/services/web-apps/mattermost.nix @@ -5,35 +5,147 @@ ... }: -with lib; - let + inherit (lib.strings) + hasInfix + hasSuffix + escapeURL + concatStringsSep + escapeShellArg + escapeShellArgs + versionAtLeast + optionalString + ; + + inherit (lib.meta) getExe; + + inherit (lib.lists) singleton; + + inherit (lib.attrsets) mapAttrsToList recursiveUpdate optionalAttrs; + + inherit (lib.options) mkOption mkPackageOption mkEnableOption; + + inherit (lib.modules) + mkRenamedOptionModule + mkMerge + mkIf + mkDefault + ; + + inherit (lib.trivial) warnIf throwIf; + + inherit (lib) types; cfg = config.services.mattermost; - database = "postgres://${cfg.localDatabaseUser}:${cfg.localDatabasePassword}@localhost:5432/${cfg.localDatabaseName}?sslmode=disable&connect_timeout=10"; + # The directory to store mutable data within dataDir. + mutableDataDir = "${cfg.dataDir}/data"; - postgresPackage = config.services.postgresql.package; + # The plugin directory. Note that this is the *post-unpack* plugin directory, + # since Mattermost unpacks plugins to put them there. (Hence, mutable data.) + pluginDir = "${mutableDataDir}/plugins"; - createDb = + # Mattermost uses this as a staging directory to unpack plugins, among possibly other things. + # Ensure that it's inside mutableDataDir since it can get rather large. + tempDir = "${mutableDataDir}/tmp"; + + # Creates a database URI. + mkDatabaseUri = { - statePath ? cfg.statePath, - localDatabaseUser ? cfg.localDatabaseUser, - localDatabasePassword ? cfg.localDatabasePassword, - localDatabaseName ? cfg.localDatabaseName, - useSudo ? true, + scheme, + user ? null, + password ? null, + escapeUserAndPassword ? true, + host ? null, + escapeHost ? true, + port ? null, + path ? null, + query ? { }, }: - '' - if ! test -e ${escapeShellArg "${statePath}/.db-created"}; then - ${lib.optionalString useSudo "${pkgs.sudo}/bin/sudo -u ${escapeShellArg config.services.postgresql.superUser} \\"} - ${postgresPackage}/bin/psql postgres -c \ - "CREATE ROLE ${localDatabaseUser} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${localDatabasePassword}'" - ${lib.optionalString useSudo "${pkgs.sudo}/bin/sudo -u ${escapeShellArg config.services.postgresql.superUser} \\"} - ${postgresPackage}/bin/createdb \ - --owner ${escapeShellArg localDatabaseUser} ${escapeShellArg localDatabaseName} - touch ${escapeShellArg "${statePath}/.db-created"} - fi - ''; + let + nullToEmpty = val: if val == null then "" else toString val; + + # Converts a list of URI attrs to a query string. + toQuery = mapAttrsToList ( + name: value: if value == null then null else (escapeURL name) + "=" + (escapeURL (toString value)) + ); + + schemePart = if scheme == null then "" else "${escapeURL scheme}://"; + userPart = + let + realUser = if escapeUserAndPassword then escapeURL user else user; + realPassword = if escapeUserAndPassword then escapeURL password else password; + in + if user == null && password == null then + "" + else if user != null && password != null then + "${realUser}:${realPassword}" + else if user != null then + realUser + else + throw "Either user or username and password must be provided"; + hostPart = + let + realHost = if escapeHost then escapeURL (nullToEmpty host) else nullToEmpty host; + in + if userPart == "" then realHost else "@" + realHost; + portPart = if port == null then "" else ":" + (toString port); + pathPart = if path == null then "" else "/" + path; + queryPart = if query == { } then "" else "?" + concatStringsSep "&" (toQuery query); + in + schemePart + userPart + hostPart + portPart + pathPart + queryPart; + + database = + let + hostIsPath = hasInfix "/" cfg.database.host; + in + if cfg.database.driver == "postgres" then + if cfg.database.peerAuth then + mkDatabaseUri { + scheme = cfg.database.driver; + inherit (cfg.database) user; + path = escapeURL cfg.database.name; + query = { + host = cfg.database.socketPath; + } // cfg.database.extraConnectionOptions; + } + else + mkDatabaseUri { + scheme = cfg.database.driver; + inherit (cfg.database) user password; + host = if hostIsPath then null else cfg.database.host; + port = if hostIsPath then null else cfg.database.port; + path = escapeURL cfg.database.name; + query = + optionalAttrs hostIsPath { host = cfg.database.host; } // cfg.database.extraConnectionOptions; + } + else if cfg.database.driver == "mysql" then + if cfg.database.peerAuth then + mkDatabaseUri { + scheme = null; + inherit (cfg.database) user; + escapeUserAndPassword = false; + host = "unix(${cfg.database.socketPath})"; + escapeHost = false; + path = escapeURL cfg.database.name; + query = cfg.database.extraConnectionOptions; + } + else + mkDatabaseUri { + scheme = null; + inherit (cfg.database) user password; + escapeUserAndPassword = false; + host = + if hostIsPath then + "unix(${cfg.database.host})" + else + "tcp(${cfg.database.host}:${toString cfg.database.port})"; + escapeHost = false; + path = escapeURL cfg.database.name; + query = cfg.database.extraConnectionOptions; + } + else + throw "Invalid database driver: ${cfg.database.driver}"; mattermostPluginDerivations = with pkgs; @@ -60,23 +172,19 @@ let else stdenv.mkDerivation { name = "${cfg.package.name}-plugins"; - nativeBuildInputs = [ - autoPatchelfHook - ] ++ mattermostPluginDerivations; - buildInputs = [ - cfg.package - ]; + nativeBuildInputs = [ autoPatchelfHook ] ++ mattermostPluginDerivations; + buildInputs = [ cfg.package ]; installPhase = '' - mkdir -p $out/data/plugins + mkdir -p $out plugins=(${ escapeShellArgs (map (plugin: "${plugin}/share/plugin.tar.gz") mattermostPluginDerivations) }) for plugin in "''${plugins[@]}"; do - hash="$(sha256sum "$plugin" | cut -d' ' -f1)" + hash="$(sha256sum "$plugin" | awk '{print $1}')" mkdir -p "$hash" tar -C "$hash" -xzf "$plugin" autoPatchelf "$hash" - GZIP_OPT=-9 tar -C "$hash" -cvzf "$out/data/plugins/$hash.tar.gz" . + GZIP_OPT=-9 tar -C "$hash" -cvzf "$out/$hash.tar.gz" . rm -rf "$hash" done ''; @@ -89,40 +197,157 @@ let }; mattermostConfWithoutPlugins = recursiveUpdate { - ServiceSettings.SiteURL = cfg.siteUrl; - ServiceSettings.ListenAddress = cfg.listenAddress; + ServiceSettings = { + SiteURL = cfg.siteUrl; + ListenAddress = "${cfg.host}:${toString cfg.port}"; + LocalModeSocketLocation = cfg.socket.path; + EnableLocalMode = cfg.socket.enable; + }; TeamSettings.SiteName = cfg.siteName; - SqlSettings.DriverName = "postgres"; - SqlSettings.DataSource = database; - PluginSettings.Directory = "${cfg.statePath}/plugins/server"; - PluginSettings.ClientDirectory = "${cfg.statePath}/plugins/client"; - } cfg.extraConfig; + SqlSettings.DriverName = cfg.database.driver; + SqlSettings.DataSource = + if cfg.database.fromEnvironment then + null + else + warnIf (!cfg.database.peerAuth && cfg.database.password != null) '' + Database password is set in Mattermost config! This password will end up in the Nix store. + + You may be able to simply set the following, if the database is on the same host + and peer authentication is enabled: + + services.mattermost.database.peerAuth = true; + + Note that this is the default if you set system.stateVersion to 25.05 or later + and the database host is localhost. + + Alternatively, you can write the following to ${ + if cfg.environmentFile == null then "your environment file" else cfg.environmentFile + }: + + MM_SQLSETTINGS_DATASOURCE=${database} + + Then set the following options: + services.mattermost.environmentFile = ""; + services.mattermost.database.fromEnvironment = true; + '' database; + FileSettings.Directory = cfg.dataDir; + PluginSettings.Directory = "${pluginDir}/server"; + PluginSettings.ClientDirectory = "${pluginDir}/client"; + LogSettings.FileLocation = cfg.logDir; + } cfg.settings; mattermostConf = recursiveUpdate mattermostConfWithoutPlugins ( - lib.optionalAttrs (mattermostPlugins != null) { - PluginSettings = { - Enable = true; - }; - } + if mattermostPlugins == null then + { } + else + { + PluginSettings = { + Enable = true; + }; + } ); mattermostConfJSON = pkgs.writeText "mattermost-config.json" (builtins.toJSON mattermostConf); in - { + imports = [ + (mkRenamedOptionModule + [ + "services" + "mattermost" + "listenAddress" + ] + [ + "services" + "mattermost" + "host" + ] + ) + (mkRenamedOptionModule + [ + "services" + "mattermost" + "localDatabaseCreate" + ] + [ + "services" + "mattermost" + "database" + "create" + ] + ) + (mkRenamedOptionModule + [ + "services" + "mattermost" + "localDatabasePassword" + ] + [ + "services" + "mattermost" + "database" + "password" + ] + ) + (mkRenamedOptionModule + [ + "services" + "mattermost" + "localDatabaseUser" + ] + [ + "services" + "mattermost" + "database" + "user" + ] + ) + (mkRenamedOptionModule + [ + "services" + "mattermost" + "localDatabaseName" + ] + [ + "services" + "mattermost" + "database" + "name" + ] + ) + (mkRenamedOptionModule + [ + "services" + "mattermost" + "extraConfig" + ] + [ + "services" + "mattermost" + "settings" + ] + ) + (mkRenamedOptionModule + [ + "services" + "mattermost" + "statePath" + ] + [ + "services" + "mattermost" + "dataDir" + ] + ) + ]; + options = { services.mattermost = { enable = mkEnableOption "Mattermost chat server"; package = mkPackageOption pkgs "mattermost" { }; - statePath = mkOption { - type = types.str; - default = "/var/lib/mattermost"; - description = "Mattermost working directory"; - }; - siteUrl = mkOption { type = types.str; example = "https://chat.example.com"; @@ -137,12 +362,77 @@ in description = "Name of this Mattermost site."; }; - listenAddress = mkOption { + host = mkOption { type = types.str; - default = ":8065"; - example = "[::1]:8065"; + default = "127.0.0.1"; + example = "0.0.0.0"; description = '' - Address and port this Mattermost instance listens to. + Host or address that this Mattermost instance listens on. + ''; + }; + + port = mkOption { + type = types.port; + default = 8065; + description = '' + Port for Mattermost server to listen on. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/mattermost"; + description = '' + Mattermost working directory. + ''; + }; + + socket = { + enable = mkEnableOption "Mattermost control socket"; + + path = mkOption { + type = types.path; + default = "${cfg.dataDir}/mattermost.sock"; + defaultText = ''''${config.mattermost.dataDir}/mattermost.sock''; + description = '' + Default location for the Mattermost control socket used by `mmctl`. + ''; + }; + + export = mkEnableOption "Export socket control to system environment variables"; + }; + + logDir = mkOption { + type = types.path; + default = + if versionAtLeast config.system.stateVersion "25.05" then + "/var/log/mattermost" + else + "${cfg.dataDir}/logs"; + defaultText = '' + if versionAtLeast config.system.stateVersion "25.05" then "/var/log/mattermost" + else "''${config.services.mattermost.dataDir}/logs"; + ''; + description = '' + Mattermost log directory. + ''; + }; + + configDir = mkOption { + type = types.path; + default = + if versionAtLeast config.system.stateVersion "25.05" then + "/etc/mattermost" + else + "${cfg.dataDir}/config"; + defaultText = '' + if versionAtLeast config.system.stateVersion "25.05" then + "/etc/mattermost" + else + "''${config.services.mattermost.dataDir}/config"; + ''; + description = '' + Mattermost config directory. ''; }; @@ -173,21 +463,8 @@ in ''; }; - extraConfig = mkOption { - type = types.attrs; - default = { }; - description = '' - Additional configuration options as Nix attribute set in config.json schema. - ''; - }; - plugins = mkOption { - type = types.listOf ( - types.oneOf [ - types.path - types.package - ] - ); + type = with types; listOf (either path package); default = [ ]; example = "[ ./com.github.moussetc.mattermost.plugin.giphy-2.0.0.tar.gz ]"; description = '' @@ -196,13 +473,25 @@ in .tar.gz files. ''; }; + + environment = mkOption { + type = with types; attrsOf (either int str); + default = { }; + description = '' + Extra environment variables to export to the Mattermost process, in the systemd unit. + ''; + example = { + MM_SERVICESETTINGS_SITEURL = "http://example.com"; + }; + }; + environmentFile = mkOption { - type = types.nullOr types.path; + type = with types; nullOr path; default = null; description = '' Environment file (see {manpage}`systemd.exec(5)` "EnvironmentFile=" section for the syntax) which sets config options - for mattermost (see [the mattermost documentation](https://docs.mattermost.com/configure/configuration-settings.html#environment-variables)). + for mattermost (see [the Mattermost documentation](https://docs.mattermost.com/configure/configuration-settings.html#environment-variables)). Settings defined in the environment file will overwrite settings set via nix or via the {option}`services.mattermost.extraConfig` @@ -213,36 +502,142 @@ in ''; }; - localDatabaseCreate = mkOption { - type = types.bool; - default = true; - description = '' - Create a local PostgreSQL database for Mattermost automatically. - ''; - }; + database = { + driver = mkOption { + type = types.enum [ + "postgres" + "mysql" + ]; + default = "postgres"; + description = '' + The database driver to use (Postgres or MySQL). + ''; + }; - localDatabaseName = mkOption { - type = types.str; - default = "mattermost"; - description = '' - Local Mattermost database name. - ''; - }; + create = mkOption { + type = types.bool; + default = true; + description = '' + Create a local PostgreSQL or MySQL database for Mattermost automatically. + ''; + }; - localDatabaseUser = mkOption { - type = types.str; - default = "mattermost"; - description = '' - Local Mattermost database username. - ''; - }; + peerAuth = mkOption { + type = types.bool; + default = versionAtLeast config.system.stateVersion "25.05" && cfg.database.host == "localhost"; + defaultText = '' + versionAtLeast config.system.stateVersion "25.05" && config.services.mattermost.database.host == "localhost" + ''; + description = '' + If set, will use peer auth instead of connecting to a Postgres server. + Use services.mattermost.database.socketPath to configure the socket path. + ''; + }; - localDatabasePassword = mkOption { - type = types.str; - default = "mmpgsecret"; - description = '' - Password for local Mattermost database user. - ''; + socketPath = mkOption { + type = types.path; + default = + if cfg.database.driver == "postgres" then "/run/postgresql" else "/run/mysqld/mysqld.sock"; + defaultText = '' + if config.services.mattermost.database.driver == "postgres" then "/run/postgresql" else "/run/mysqld/mysqld.sock"; + ''; + description = '' + The database (Postgres or MySQL) socket path. + ''; + }; + + fromEnvironment = mkOption { + type = types.bool; + default = false; + description = '' + Use services.mattermost.environmentFile to configure the database instead of writing the database URI + to the Nix store. Useful if you use password authentication with peerAuth set to false. + ''; + }; + + name = mkOption { + type = types.str; + default = "mattermost"; + description = '' + Local Mattermost database name. + ''; + }; + + host = mkOption { + type = types.str; + default = "localhost"; + example = "127.0.0.1"; + description = '' + Host to use for the database. Can also be set to a path if you'd like to connect + to a socket using a username and password. + ''; + }; + + port = mkOption { + type = types.port; + default = if cfg.database.driver == "postgres" then 5432 else 3306; + defaultText = '' + if config.services.mattermost.database.type == "postgres" then 5432 else 3306 + ''; + example = 3306; + description = '' + Port to use for the database. + ''; + }; + + user = mkOption { + type = types.str; + default = "mattermost"; + description = '' + Local Mattermost database username. + ''; + }; + + password = mkOption { + type = types.str; + default = "mmpgsecret"; + description = '' + Password for local Mattermost database user. If set and peerAuth is not true, + will cause a warning nagging you to use environmentFile instead since it will + end up in the Nix store. + ''; + }; + + extraConnectionOptions = mkOption { + type = with types; attrsOf (either int str); + default = + if cfg.database.driver == "postgres" then + { + sslmode = "disable"; + connect_timeout = 30; + } + else if cfg.database.driver == "mysql" then + { + charset = "utf8mb4,utf8"; + writeTimeout = "30s"; + readTimeout = "30s"; + } + else + throw "Invalid database driver ${cfg.database.driver}"; + defaultText = '' + if config.mattermost.database.driver == "postgres" then + { + sslmode = "disable"; + connect_timeout = 30; + } + else if config.mattermost.database.driver == "mysql" then + { + charset = "utf8mb4,utf8"; + writeTimeout = "30s"; + readTimeout = "30s"; + } + else + throw "Invalid database driver"; + ''; + description = '' + Extra options that are placed in the connection URI's query parameters. + ''; + }; }; user = mkOption { @@ -261,6 +656,14 @@ in ''; }; + settings = mkOption { + type = types.attrs; + default = { }; + description = '' + Additional configuration options as Nix attribute set in config.json schema. + ''; + }; + matterircd = { enable = mkEnableOption "Mattermost IRC bridge"; package = mkPackageOption pkgs "matterircd" { }; @@ -282,83 +685,235 @@ in config = mkMerge [ (mkIf cfg.enable { - users.users = optionalAttrs (cfg.user == "mattermost") { - mattermost = { + users.users = { + ${cfg.user} = { group = cfg.group; - uid = config.ids.uids.mattermost; - home = cfg.statePath; + uid = mkIf (cfg.user == "mattermost") config.ids.uids.mattermost; + home = cfg.dataDir; + isSystemUser = true; + packages = [ cfg.package ]; }; }; - users.groups = optionalAttrs (cfg.group == "mattermost") { - mattermost.gid = config.ids.gids.mattermost; + users.groups = { + ${cfg.group} = { + gid = mkIf (cfg.group == "mattermost") config.ids.gids.mattermost; + }; }; - services.postgresql.enable = cfg.localDatabaseCreate; + services.postgresql = mkIf (cfg.database.driver == "postgres" && cfg.database.create) { + enable = true; + ensureDatabases = singleton cfg.database.name; + ensureUsers = singleton { + name = + throwIf + (cfg.database.peerAuth && (cfg.database.user != cfg.user || cfg.database.name != cfg.database.user)) + '' + Mattermost database peer auth is enabled and the user, database user, or database name mismatch. + Peer authentication will not work. + '' + cfg.database.user; + ensureDBOwnership = true; + }; + }; - # The systemd service will fail to execute the preStart hook - # if the WorkingDirectory does not exist - systemd.tmpfiles.settings."10-mattermost".${cfg.statePath}.d = { }; + services.mysql = mkIf (cfg.database.driver == "mysql" && cfg.database.create) { + enable = true; + package = mkDefault pkgs.mariadb; + ensureDatabases = singleton cfg.database.name; + ensureUsers = singleton { + name = cfg.database.user; + ensurePermissions = { + "${cfg.database.name}.*" = "ALL PRIVILEGES"; + }; + }; + settings = rec { + mysqld = { + collation-server = mkDefault "utf8mb4_general_ci"; + init-connect = mkDefault "SET NAMES utf8mb4"; + character-set-server = mkDefault "utf8mb4"; + }; + mysqld_safe = mysqld; + }; + }; - systemd.services.mattermost = { + environment = { + variables = mkIf cfg.socket.export { + MMCTL_LOCAL = "true"; + MMCTL_LOCAL_SOCKET_PATH = cfg.socket.path; + }; + }; + + systemd.tmpfiles.rules = + [ + "d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -" + "d ${cfg.logDir} 0750 ${cfg.user} ${cfg.group} - -" + "d ${cfg.configDir} 0750 ${cfg.user} ${cfg.group} - -" + "d ${mutableDataDir} 0750 ${cfg.user} ${cfg.group} - -" + + # Make sure tempDir exists and is not a symlink. + "R- ${tempDir} - - - - -" + "d= ${tempDir} 0750 ${cfg.user} ${cfg.group} - -" + + # Ensure that pluginDir is a directory, as it could be a symlink on prior versions. + "r- ${pluginDir} - - - - -" + "d= ${pluginDir} 0750 ${cfg.user} ${cfg.group} - -" + + # Ensure that the plugin directories exist. + "d= ${mattermostConf.PluginSettings.Directory} 0750 ${cfg.user} ${cfg.group} - -" + "d= ${mattermostConf.PluginSettings.ClientDirectory} 0750 ${cfg.user} ${cfg.group} - -" + + # Link in some of the immutable data directories. + "L+ ${cfg.dataDir}/bin - - - - ${cfg.package}/bin" + "L+ ${cfg.dataDir}/fonts - - - - ${cfg.package}/fonts" + "L+ ${cfg.dataDir}/i18n - - - - ${cfg.package}/i18n" + "L+ ${cfg.dataDir}/templates - - - - ${cfg.package}/templates" + "L+ ${cfg.dataDir}/client - - - - ${cfg.package}/client" + ] + ++ ( + if mattermostPlugins == null then + # Create the plugin tarball directory if it's a symlink. + [ + "r- ${cfg.dataDir}/plugins - - - - -" + "d= ${cfg.dataDir}/plugins 0750 ${cfg.user} ${cfg.group} - -" + ] + else + # Symlink the plugin tarball directory, removing anything existing. + [ "L+ ${cfg.dataDir}/plugins - - - - ${mattermostPlugins}" ] + ); + + systemd.services.mattermost = rec { description = "Mattermost chat service"; wantedBy = [ "multi-user.target" ]; - after = [ - "network.target" - "postgresql.service" + after = mkMerge [ + [ "network.target" ] + (mkIf (cfg.database.driver == "postgres" && cfg.database.create) [ "postgresql.service" ]) + (mkIf (cfg.database.driver == "mysql" && cfg.database.create) [ "mysql.service" ]) + ]; + requires = after; + + environment = mkMerge [ + { + # Use tempDir as this can get rather large, especially if Mattermost unpacks a large number of plugins. + TMPDIR = tempDir; + } + cfg.environment ]; preStart = '' - mkdir -p "${cfg.statePath}"/{data,config,logs,plugins} - mkdir -p "${cfg.statePath}/plugins"/{client,server} - ln -sf ${cfg.package}/{bin,fonts,i18n,templates,client} "${cfg.statePath}" + dataDir=${escapeShellArg cfg.dataDir} + configDir=${escapeShellArg cfg.configDir} + logDir=${escapeShellArg cfg.logDir} + package=${escapeShellArg cfg.package} + nixConfig=${escapeShellArg mattermostConfJSON} '' - + lib.optionalString (mattermostPlugins != null) '' - rm -rf "${cfg.statePath}/data/plugins" - ln -sf ${mattermostPlugins}/data/plugins "${cfg.statePath}/data" - '' - + lib.optionalString (!cfg.mutableConfig) '' - rm -f "${cfg.statePath}/config/config.json" - ${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${cfg.package}/config/config.json ${mattermostConfJSON} > "${cfg.statePath}/config/config.json" - '' - + lib.optionalString cfg.mutableConfig '' - if ! test -e "${cfg.statePath}/config/.initial-created"; then - rm -f ${cfg.statePath}/config/config.json - ${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${cfg.package}/config/config.json ${mattermostConfJSON} > "${cfg.statePath}/config/config.json" - touch "${cfg.statePath}/config/.initial-created" + + optionalString (versionAtLeast config.system.stateVersion "25.05") '' + # Migrate configs in the pre-25.05 directory structure. + oldConfig="$dataDir/config/config.json" + newConfig="$configDir/config.json" + if [ "$oldConfig" != "$newConfig" ] && [ -f "$oldConfig" ] && [ ! -f "$newConfig" ]; then + # Migrate the legacy config location to the new config location + echo "Moving legacy config at $oldConfig to $newConfig" >&2 + mkdir -p "$configDir" + mv "$oldConfig" "$newConfig" + touch "$configDir/.initial-created" + fi + + # Logs too. + oldLogs="$dataDir/logs" + newLogs="$logDir" + if [ "$oldLogs" != "$newLogs" ] && [ -d "$oldLogs" ]; then + # Migrate the legacy log location to the new log location. + # Allow this to fail if there aren't any logs to move. + echo "Moving legacy logs at $oldLogs to $newLogs" >&2 + mkdir -p "$newLogs" + mv "$oldLogs"/* "$newLogs" || true fi '' - + lib.optionalString (cfg.mutableConfig && cfg.preferNixConfig) '' - new_config="$(${pkgs.jq}/bin/jq -s '.[0] * .[1]' "${cfg.statePath}/config/config.json" ${mattermostConfJSON})" - - rm -f "${cfg.statePath}/config/config.json" - echo "$new_config" > "${cfg.statePath}/config/config.json" + + optionalString (!cfg.mutableConfig) '' + ${getExe pkgs.jq} -s '.[0] * .[1]' "$package/config/config.json" "$nixConfig" > "$configDir/config.json" '' - + lib.optionalString cfg.localDatabaseCreate (createDb { }) - + '' - # Don't change permissions recursively on the data, current, and symlinked directories (see ln -sf command above). - # This dramatically decreases startup times for installations with a lot of files. - find . -maxdepth 1 -not -name data -not -name client -not -name templates -not -name i18n -not -name fonts -not -name bin -not -name . \ - -exec chown "${cfg.user}:${cfg.group}" -R {} \; -exec chmod u+rw,g+r,o-rwx -R {} \; - - chown "${cfg.user}:${cfg.group}" "${cfg.statePath}/data" . - chmod u+rw,g+r,o-rwx "${cfg.statePath}/data" . + + optionalString cfg.mutableConfig '' + if [ ! -e "$configDir/.initial-created" ]; then + ${getExe pkgs.jq} -s '.[0] * .[1]' "$package/config/config.json" "$nixConfig" > "$configDir/config.json" + touch "$configDir/.initial-created" + fi + '' + + optionalString (cfg.mutableConfig && cfg.preferNixConfig) '' + echo "$(${getExe pkgs.jq} -s '.[0] * .[1]' "$configDir/config.json" "$nixConfig")" > "$configDir/config.json" ''; - serviceConfig = { - PermissionsStartOnly = true; - User = cfg.user; - Group = cfg.group; - ExecStart = "${cfg.package}/bin/mattermost"; - WorkingDirectory = "${cfg.statePath}"; - Restart = "always"; - RestartSec = "10"; - LimitNOFILE = "49152"; - EnvironmentFile = cfg.environmentFile; - }; - unitConfig.JoinsNamespaceOf = mkIf cfg.localDatabaseCreate "postgresql.service"; + serviceConfig = mkMerge [ + { + User = cfg.user; + Group = cfg.group; + ExecStart = "${getExe cfg.package} --config ${cfg.configDir}/config.json"; + ReadWritePaths = [ + cfg.dataDir + cfg.logDir + cfg.configDir + ]; + UMask = "0027"; + Restart = "always"; + RestartSec = 10; + LimitNOFILE = 49152; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RestrictNamespaces = true; + RestrictSUIDSGID = true; + EnvironmentFile = cfg.environmentFile; + WorkingDirectory = cfg.dataDir; + } + (mkIf (cfg.dataDir == "/var/lib/mattermost") { + StateDirectory = baseNameOf cfg.dataDir; + StateDirectoryMode = "0750"; + }) + (mkIf (cfg.logDir == "/var/log/mattermost") { + LogsDirectory = baseNameOf cfg.logDir; + LogsDirectoryMode = "0750"; + }) + (mkIf (cfg.configDir == "/etc/mattermost") { + ConfigurationDirectory = baseNameOf cfg.configDir; + ConfigurationDirectoryMode = "0750"; + }) + ]; + + unitConfig.JoinsNamespaceOf = mkMerge [ + (mkIf (cfg.database.driver == "postgres" && cfg.database.create) [ "postgresql.service" ]) + (mkIf (cfg.database.driver == "mysql" && cfg.database.create) [ "mysql.service" ]) + ]; }; + + assertions = [ + { + # Make sure the URL doesn't have a trailing slash + assertion = !(hasSuffix "/" cfg.siteUrl); + message = '' + services.mattermost.siteUrl should not have a trailing "/". + ''; + } + { + # Make sure this isn't a host/port pair + assertion = !(hasInfix ":" cfg.host && !(hasInfix "[" cfg.host) && !(hasInfix "]" cfg.host)); + message = '' + services.mattermost.host should not include a port. Use services.mattermost.host for the address + or hostname, and services.mattermost.port to specify the port separately. + ''; + } + ]; }) (mkIf cfg.matterircd.enable { systemd.services.matterircd = { @@ -367,7 +922,7 @@ in serviceConfig = { User = "nobody"; Group = "nogroup"; - ExecStart = "${cfg.matterircd.package}/bin/matterircd ${escapeShellArgs cfg.matterircd.parameters}"; + ExecStart = "${getExe cfg.matterircd.package} ${escapeShellArgs cfg.matterircd.parameters}"; WorkingDirectory = "/tmp"; PrivateTmp = true; Restart = "always"; @@ -376,4 +931,6 @@ in }; }) ]; + + meta.maintainers = with lib.maintainers; [ numinit ]; } diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 622d43d4080b..83c9c52b81ad 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -593,7 +593,7 @@ in { matrix-synapse-workers = handleTest ./matrix/synapse-workers.nix {}; mautrix-meta-postgres = handleTest ./matrix/mautrix-meta-postgres.nix {}; mautrix-meta-sqlite = handleTest ./matrix/mautrix-meta-sqlite.nix {}; - mattermost = handleTest ./mattermost.nix {}; + mattermost = handleTest ./mattermost {}; mealie = handleTest ./mealie.nix {}; mediamtx = handleTest ./mediamtx.nix {}; mediatomb = handleTest ./mediatomb.nix {}; diff --git a/nixos/tests/mattermost.nix b/nixos/tests/mattermost.nix deleted file mode 100644 index a39033ced31d..000000000000 --- a/nixos/tests/mattermost.nix +++ /dev/null @@ -1,169 +0,0 @@ -import ./make-test-python.nix ( - { pkgs, lib, ... }: - let - host = "smoke.test"; - port = "8065"; - url = "http://${host}:${port}"; - siteName = "NixOS Smoke Tests, Inc."; - - makeMattermost = - mattermostConfig: - { config, ... }: - { - environment.systemPackages = [ - pkgs.mattermost - pkgs.curl - pkgs.jq - ]; - networking.hosts = { - "127.0.0.1" = [ host ]; - }; - services.mattermost = lib.recursiveUpdate { - enable = true; - inherit siteName; - listenAddress = "0.0.0.0:${port}"; - siteUrl = url; - extraConfig = { - SupportSettings.AboutLink = "https://nixos.org"; - }; - } mattermostConfig; - }; - in - { - name = "mattermost"; - - nodes = { - mutable = makeMattermost { - mutableConfig = true; - extraConfig.SupportSettings.HelpLink = "https://search.nixos.org"; - }; - mostlyMutable = makeMattermost { - mutableConfig = true; - preferNixConfig = true; - plugins = - let - mattermostDemoPlugin = pkgs.fetchurl { - url = "https://github.com/mattermost/mattermost-plugin-demo/releases/download/v0.9.0/com.mattermost.demo-plugin-0.9.0.tar.gz"; - sha256 = "1h4qi34gcxcx63z8wiqcf2aaywmvv8lys5g8gvsk13kkqhlmag25"; - }; - in - [ - mattermostDemoPlugin - ]; - }; - immutable = makeMattermost { - package = pkgs.mattermost.overrideAttrs (prev: { - webapp = prev.webapp.overrideAttrs (prevWebapp: { - # Ensure that users can add patches. - postPatch = - prevWebapp.postPatch or "" - + '' - substituteInPlace channels/src/root.html --replace-fail "Mattermost" "Patched Mattermost" - ''; - }); - }); - mutableConfig = false; - extraConfig.SupportSettings.HelpLink = "https://search.nixos.org"; - }; - environmentFile = makeMattermost { - mutableConfig = false; - extraConfig.SupportSettings.AboutLink = "https://example.org"; - environmentFile = pkgs.writeText "mattermost-env" '' - MM_SUPPORTSETTINGS_ABOUTLINK=https://nixos.org - ''; - }; - }; - - testScript = - let - expectConfig = - jqExpression: - pkgs.writeShellScript "expect-config" '' - set -euo pipefail - echo "Expecting config to match: "${lib.escapeShellArg jqExpression} >&2 - curl ${lib.escapeShellArg url} >/dev/null - config="$(curl ${lib.escapeShellArg "${url}/api/v4/config/client?format=old"})" - echo "Config: $(echo "$config" | ${pkgs.jq}/bin/jq)" >&2 - [[ "$(echo "$config" | ${pkgs.jq}/bin/jq -r ${lib.escapeShellArg ".SiteName == $siteName and .Version == ($mattermostName / $sep)[-1] and (${jqExpression})"} --arg siteName ${lib.escapeShellArg siteName} --arg mattermostName ${lib.escapeShellArg pkgs.mattermost.name} --arg sep '-')" = "true" ]] - ''; - - setConfig = - jqExpression: - pkgs.writeShellScript "set-config" '' - set -euo pipefail - mattermostConfig=/var/lib/mattermost/config/config.json - newConfig="$(${pkgs.jq}/bin/jq -r ${lib.escapeShellArg jqExpression} $mattermostConfig)" - rm -f $mattermostConfig - echo "$newConfig" > "$mattermostConfig" - ''; - - in - '' - start_all() - - ## Mutable node tests ## - mutable.wait_for_unit("mattermost.service") - mutable.wait_for_open_port(8065) - mutable.succeed("curl -L http://localhost:8065/index.html | grep '${siteName}'") - mutable.succeed("curl -L http://localhost:8065/index.html | grep 'Mattermost'") - - # Get the initial config - mutable.succeed("${expectConfig ''.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"''}") - - # Edit the config - mutable.succeed("${setConfig ''.SupportSettings.AboutLink = "https://mattermost.com"''}") - mutable.succeed("${setConfig ''.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"''}") - mutable.systemctl("restart mattermost.service") - mutable.wait_for_open_port(8065) - - # AboutLink and HelpLink should be changed - mutable.succeed("${expectConfig ''.AboutLink == "https://mattermost.com" and .HelpLink == "https://nixos.org/nixos/manual"''}") - - ## Mostly mutable node tests ## - mostlyMutable.wait_for_unit("mattermost.service") - mostlyMutable.wait_for_open_port(8065) - mostlyMutable.succeed("curl -L http://localhost:8065/index.html | grep '${siteName}'") - mostlyMutable.succeed("curl -L http://localhost:8065/index.html | grep 'Mattermost'") - - # Get the initial config - mostlyMutable.succeed("${expectConfig ''.AboutLink == "https://nixos.org"''}") - - # Edit the config - mostlyMutable.succeed("${setConfig ''.SupportSettings.AboutLink = "https://mattermost.com"''}") - mostlyMutable.succeed("${setConfig ''.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"''}") - mostlyMutable.systemctl("restart mattermost.service") - mostlyMutable.wait_for_open_port(8065) - - # AboutLink should be overridden by NixOS configuration; HelpLink should be what we set above - mostlyMutable.succeed("${expectConfig ''.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual"''}") - - ## Immutable node tests ## - immutable.wait_for_unit("mattermost.service") - immutable.wait_for_open_port(8065) - # Since we patched it, it doesn't replace the site name at runtime anymore - immutable.succeed("curl -L http://localhost:8065/index.html | grep 'Patched Mattermost'") - - # Get the initial config - immutable.succeed("${expectConfig ''.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"''}") - - # Edit the config - immutable.succeed("${setConfig ''.SupportSettings.AboutLink = "https://mattermost.com"''}") - immutable.succeed("${setConfig ''.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"''}") - immutable.systemctl("restart mattermost.service") - immutable.wait_for_open_port(8065) - - # Our edits should be ignored on restart - immutable.succeed("${expectConfig ''.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"''}") - - - ## Environment File node tests ## - environmentFile.wait_for_unit("mattermost.service") - environmentFile.wait_for_open_port(8065) - environmentFile.succeed("curl -L http://localhost:8065/index.html | grep '${siteName}'") - environmentFile.succeed("curl -L http://localhost:8065/index.html | grep 'Mattermost'") - - # Settings in the environment file should override settings set otherwise - environmentFile.succeed("${expectConfig ''.AboutLink == "https://nixos.org"''}") - ''; - } -) diff --git a/nixos/tests/mattermost/default.nix b/nixos/tests/mattermost/default.nix new file mode 100644 index 000000000000..99ad4b110118 --- /dev/null +++ b/nixos/tests/mattermost/default.nix @@ -0,0 +1,537 @@ +import ../make-test-python.nix ( + { pkgs, lib, ... }: + let + host = "smoke.test"; + port = 8065; + url = "http://${host}:${toString port}"; + siteName = "NixOS Smoke Tests, Inc."; + + makeMattermost = + mattermostConfig: extraConfig: + lib.mkMerge [ + ( + { config, ... }: + { + environment = { + systemPackages = [ + pkgs.mattermost + pkgs.curl + pkgs.jq + ]; + }; + networking.hosts = { + "127.0.0.1" = [ host ]; + }; + + # Assume that Postgres won't update across stateVersion. + services.postgresql = { + package = lib.mkForce pkgs.postgresql; + initialScript = lib.mkIf (!config.services.mattermost.database.peerAuth) ( + pkgs.writeText "init.sql" '' + create role ${config.services.mattermost.database.user} with login nocreatedb nocreaterole encrypted password '${config.services.mattermost.database.password}'; + '' + ); + }; + + system.stateVersion = lib.mkDefault "25.05"; + + services.mattermost = lib.recursiveUpdate { + enable = true; + inherit siteName; + host = "0.0.0.0"; + inherit port; + siteUrl = url; + socket = { + enable = true; + export = true; + }; + database = { + peerAuth = lib.mkDefault true; + }; + settings = { + SupportSettings.AboutLink = "https://nixos.org"; + PluginSettings.AutomaticPrepackagedPlugins = false; + AnnouncementSettings = { + # Disable this since it doesn't work in the sandbox and causes a timeout. + AdminNoticesEnabled = false; + UserNoticesEnabled = false; + }; + }; + } mattermostConfig; + + # Upgrade to the latest Mattermost. + specialisation.latest.configuration = { + services.mattermost.package = lib.mkForce pkgs.mattermostLatest; + system.stateVersion = lib.mkVMOverride "25.05"; + }; + } + ) + extraConfig + ]; + + makeMysql = + mattermostConfig: extraConfig: + lib.mkMerge [ + mattermostConfig + ( + { pkgs, config, ... }: + { + services.mattermost.database = { + driver = lib.mkForce "mysql"; + peerAuth = lib.mkForce true; + }; + } + ) + extraConfig + ]; + in + { + name = "mattermost"; + + nodes = rec { + postgresMutable = + makeMattermost + { + mutableConfig = true; + settings.SupportSettings.HelpLink = "https://search.nixos.org"; + } + { + # Last version to support the "old" config layout. + system.stateVersion = lib.mkForce "24.11"; + + # First version to support the "new" config layout. + specialisation.upgrade.configuration.system.stateVersion = lib.mkVMOverride "25.05"; + }; + postgresMostlyMutable = makeMattermost { + mutableConfig = true; + preferNixConfig = true; + plugins = with pkgs; [ + # Build the demo plugin. + (mattermost.buildPlugin { + pname = "mattermost-plugin-starter-template"; + version = "0.1.0"; + src = fetchFromGitHub { + owner = "mattermost"; + repo = "mattermost-plugin-starter-template"; + # Newer versions have issues with their dependency lockfile. + rev = "7c98e89ac1a268ce8614bc665571b7bbc9a70df2"; + hash = "sha256-uyfxB0GZ45qL9ssWUord0eKQC6S0TlCTtjTOXWtK4H0="; + }; + vendorHash = "sha256-Jl4F9YkHNqiFP9/yeyi4vTntqxMk/J1zhEP6QLSvJQA="; + npmDepsHash = "sha256-z08nc4XwT+uQjQlZiUydJyh8mqeJoYdPFWuZpw9k99s="; + }) + + # Build the todos plugin. + (mattermost.buildPlugin { + pname = "mattermost-plugin-todo"; + version = "0.8-pre"; + src = fetchFromGitHub { + owner = "mattermost-community"; + repo = "mattermost-plugin-todo"; + # 0.7.1 didn't work, seems to use an older set of node dependencies. + rev = "f25dc91ea401c9f0dcd4abcebaff10eb8b9836e5"; + hash = "sha256-OM+m4rTqVtolvL5tUE8RKfclqzoe0Y38jLU60Pz7+HI="; + }; + vendorHash = "sha256-5KpechSp3z/Nq713PXYruyNxveo6CwrCSKf2JaErbgg="; + npmDepsHash = "sha256-o2UOEkwb8Vx2lDWayNYgng0GXvmS6lp/ExfOq3peyMY="; + extraGoModuleAttrs = { + npmFlags = [ "--legacy-peer-deps" ]; + }; + }) + ]; + } { }; + postgresImmutable = makeMattermost { + package = pkgs.mattermost.overrideAttrs (prev: { + webapp = prev.webapp.overrideAttrs (prevWebapp: { + # Ensure that users can add patches. + postPatch = + prevWebapp.postPatch or "" + + '' + substituteInPlace channels/src/root.html --replace-fail "Mattermost" "Patched Mattermost" + ''; + }); + }); + mutableConfig = false; + + # Make sure something other than the default works. + user = "mmuser"; + group = "mmgroup"; + + database = { + # Ensure that this gets tested on Postgres. + peerAuth = false; + }; + settings.SupportSettings.HelpLink = "https://search.nixos.org"; + } { }; + postgresEnvironmentFile = makeMattermost { + mutableConfig = false; + database.fromEnvironment = true; + settings.SupportSettings.AboutLink = "https://example.org"; + environmentFile = pkgs.writeText "mattermost-env" '' + MM_SQLSETTINGS_DATASOURCE=postgres:///mattermost?host=/run/postgresql + MM_SUPPORTSETTINGS_ABOUTLINK=https://nixos.org + ''; + } { }; + + mysqlMutable = makeMysql postgresMutable { }; + mysqlMostlyMutable = makeMysql postgresMostlyMutable { }; + mysqlImmutable = makeMysql postgresImmutable { + # Let's try to use this on MySQL. + services.mattermost.database = { + peerAuth = lib.mkForce true; + user = lib.mkForce "mmuser"; + name = lib.mkForce "mmuser"; + }; + }; + mysqlEnvironmentFile = makeMysql postgresEnvironmentFile { + services.mattermost.environmentFile = lib.mkForce ( + pkgs.writeText "mattermost-env" '' + MM_SQLSETTINGS_DATASOURCE=mattermost@unix(/run/mysqld/mysqld.sock)/mattermost?charset=utf8mb4,utf8&writeTimeout=30s + MM_SUPPORTSETTINGS_ABOUTLINK=https://nixos.org + '' + ); + }; + }; + + testScript = + { nodes, ... }: + let + expectConfig = pkgs.writeShellScript "expect-config" '' + set -euo pipefail + config="$(curl ${lib.escapeShellArg "${url}/api/v4/config/client?format=old"})" + echo "Config: $(echo "$config" | ${pkgs.jq}/bin/jq)" >&2 + [[ "$(echo "$config" | ${pkgs.jq}/bin/jq -r ${lib.escapeShellArg ".SiteName == $siteName and .Version == $mattermostVersion and "}"($1)" --arg siteName ${lib.escapeShellArg siteName} --arg mattermostVersion "$2" --arg sep '-')" = "true" ]] + ''; + + setConfig = pkgs.writeShellScript "set-config" '' + set -eo pipefail + mattermostConfig=/etc/mattermost/config.json + nixosVersion="$2" + if [ -z "$nixosVersion" ]; then + nixosVersion="$(nixos-version)" + fi + nixosVersion="$(echo "$nixosVersion" | sed -nr 's/^([0-9]{2})\.([0-9]{2}).*/\1\2/p')" + echo "NixOS version: $nixosVersion" >&2 + if [ "$nixosVersion" -lt 2505 ]; then + mattermostConfig=/var/lib/mattermost/config/config.json + fi + newConfig="$(${pkgs.jq}/bin/jq -r "$1" "$mattermostConfig")" + echo "New config @ $mattermostConfig: $(echo "$newConfig" | ${pkgs.jq}/bin/jq)" >&2 + truncate -s 0 "$mattermostConfig" + echo "$newConfig" >> "$mattermostConfig" + ''; + + expectPlugins = pkgs.writeShellScript "expect-plugins" '' + set -euo pipefail + case "$1" in + ""|*[!0-9]*) + plugins="$(curl ${lib.escapeShellArg "${url}/api/v4/plugins/webapp"})" + echo "Plugins: $(echo "$plugins" | ${pkgs.jq}/bin/jq)" >&2 + [[ "$(echo "$plugins" | ${pkgs.jq}/bin/jq -r "$1")" == "true" ]] + ;; + *) + code="$(curl -s -o /dev/null -w "%{http_code}" ${lib.escapeShellArg "${url}/api/v4/plugins/webapp"})" + [[ "$code" == "$1" ]] + ;; + esac + ''; + + ensurePost = pkgs.writeShellScript "ensure-post" '' + set -euo pipefail + + url="$1" + failIfNotFound="$2" + + # Make sure the user exists + thingExists='(type == "array" and length > 0)' + userExists="($thingExists and ("'.[0].username == "nixos"))' + if mmctl user list --json | jq | tee /dev/stderr | jq -e "$userExists | not"; then + if [ "$failIfNotFound" -ne 0 ]; then + echo "User didn't exist!" >&2 + exit 1 + else + mmctl user create \ + --email tests@nixos.org \ + --username nixos --password nixosrules --system-admin --email-verified >&2 + + # Make sure the user exists. + while mmctl user list --json | jq | tee /dev/stderr | jq -e "$userExists | not"; do + sleep 1 + done + fi + fi + + # Auth. + mmctl auth login "$url" --name nixos --username nixos --password nixosrules + + # Make sure the team exists + teamExists="($thingExists and ("'.[0].display_name == "NixOS Smoke Tests, Inc."))' + if mmctl team list --json | jq | tee /dev/stderr | jq -e "$teamExists | not"; then + if [ "$failIfNotFound" -ne 0 ]; then + echo "Team didn't exist!" >&2 + exit 1 + else + mmctl team create \ + --name nixos \ + --display-name "NixOS Smoke Tests, Inc." + + # Teams take a second to create. + while mmctl team list --json | jq | tee /dev/stderr | jq -e "$teamExists | not"; do + sleep 1 + done + + # Add the user. + mmctl team users add nixos tests@nixos.org + fi + fi + + authToken="$(cat ~/.config/mmctl/config | jq -r '.nixos.authToken')" + authHeader="Authorization: Bearer $authToken" + acceptHeader="Accept: application/json; charset=UTF-8" + + # Make sure the test post exists. + postContents="pls enjoy this NixOS meme I made" + postAttachment=${./test.jpg} + postAttachmentSize="$(stat -c%s $postAttachment)" + postAttachmentHash="$(sha256sum $postAttachment | awk '{print $1}')" + postAttachmentId="" + postPredicate='select(.message == $message and (.file_ids | length) > 0 and (.metadata.files[0].size | tonumber) == ($size | tonumber))' + postExists="($thingExists and ("'(.[] | '"$postPredicate"' | length) > 0))' + if mmctl post list nixos:off-topic --json | jq | tee /dev/stderr | jq --arg message "$postContents" --arg size "$postAttachmentSize" -e "$postExists | not"; then + if [ "$failIfNotFound" -ne 0 ]; then + echo "Post didn't exist!" >&2 + exit 1 + else + # Can't use mmcli for this seemingly. + channelId="$(mmctl channel list nixos --json | jq | tee /dev/stderr | jq -r '.[] | select(.name == "off-topic") | .id')" + echo "Channel ID: $channelId" >&2 + + # Upload the file. + echo "Uploading file at $postAttachment (size: $postAttachmentSize)..." >&2 + postAttachmentId="$(curl "$url/api/v4/files" -X POST -H "$acceptHeader" -H "$authHeader" \ + -F "files=@$postAttachment" -F "channel_id=$channelId" -F "client_ids=test" | jq | tee /dev/stderr | jq -r '.file_infos[0].id')" + + # Create the post with it attached. + postJson="$(echo '{}' | jq -c --arg channelId "$channelId" --arg message "$postContents" --arg fileId "$postAttachmentId" \ + '{channel_id: $channelId, message: $message, file_ids: [$fileId]}')" + echo "Creating post with contents $postJson..." >&2 + curl "$url/api/v4/posts" -X POST -H "$acceptHeader" -H "$authHeader" --json "$postJson" | jq >&2 + fi + fi + + if mmctl post list nixos:off-topic --json | jq | tee /dev/stderr | jq --arg message "$postContents" --arg size "$postAttachmentSize" -e "$postExists"; then + # Get the attachment ID. + getPostAttachmentId=".[] | $postPredicate | .file_ids[0]" + postAttachmentId="$(mmctl post list nixos:off-topic --json | jq | tee /dev/stderr | \ + jq --arg message "$postContents" --arg size "$postAttachmentSize" -r "$getPostAttachmentId")" + + echo "Expected post attachment hash: $postAttachmentHash" >&2 + actualPostAttachmentHash="$(curl "$url/api/v4/files/$postAttachmentId?download=1" -H "$authHeader" | sha256sum | awk '{print $1}')" + echo "Actual post attachment hash: $postAttachmentHash" >&2 + if [ "$actualPostAttachmentHash" != "$postAttachmentHash" ]; then + echo "Post attachment hash mismatched!" >&2 + exit 1 + else + echo "Post attachment hash was OK!" >&2 + exit 0 + fi + else + echo "Post didn't exist when it should have!" >&2 + exit 1 + fi + ''; + in + '' + import shlex + + def wait_mattermost_up(node, site_name="${siteName}"): + node.systemctl("start mattermost.service") + node.wait_for_unit("mattermost.service") + node.wait_for_open_port(8065) + node.succeed(f"curl {shlex.quote('${url}')} >/dev/null") + node.succeed(f"curl {shlex.quote('${url}')}/index.html | grep {shlex.quote(site_name)}") + + def restart_mattermost(node, site_name="${siteName}"): + node.systemctl("restart mattermost.service") + wait_mattermost_up(node, site_name) + + def expect_config(node, mattermost_version, *configs): + for config in configs: + node.succeed(f"${expectConfig} {shlex.quote(config)} {shlex.quote(mattermost_version)}") + + def expect_plugins(node, jq_or_code): + node.succeed(f"${expectPlugins} {shlex.quote(str(jq_or_code))}") + + def ensure_post(node, fail_if_not_found=False): + node.succeed(f"${ensurePost} {shlex.quote('${url}')} {1 if fail_if_not_found else 0}") + + def set_config(node, *configs, nixos_version='25.05'): + for config in configs: + args = [shlex.quote("${setConfig}")] + args.append(shlex.quote(config)) + if nixos_version: + args.append(shlex.quote(str(nixos_version))) + node.succeed(' '.join(args)) + + def run_mattermost_tests(mutableToplevel: str, mutable, + mostlyMutableToplevel: str, mostlyMutable, + immutableToplevel: str, immutable, + environmentFileToplevel: str, environmentFile): + esr, latest = '${pkgs.mattermost.version}', '${pkgs.mattermostLatest.version}' + + ## Mutable node tests ## + mutable.start() + wait_mattermost_up(mutable) + + # Get the initial config + expect_config(mutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"') + + # Edit the config and make a post + set_config( + mutable, + '.SupportSettings.AboutLink = "https://mattermost.com"', + '.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"', + nixos_version='24.11' # Default 'mutable' config is an old version + ) + ensure_post(mutable) + restart_mattermost(mutable) + + # AboutLink and HelpLink should be changed, and the post should exist + expect_config(mutable, esr, '.AboutLink == "https://mattermost.com" and .HelpLink == "https://nixos.org/nixos/manual"') + ensure_post(mutable, fail_if_not_found=True) + + # Switch to the newer config + mutable.succeed(f"{mutableToplevel}/specialisation/upgrade/bin/switch-to-configuration switch") + wait_mattermost_up(mutable) + + # AboutLink and HelpLink should be changed, still, and the post should still exist + expect_config(mutable, esr, '.AboutLink == "https://mattermost.com" and .HelpLink == "https://nixos.org/nixos/manual"') + ensure_post(mutable, fail_if_not_found=True) + + # Switch to the latest Mattermost version + mutable.succeed(f"{mutableToplevel}/specialisation/latest/bin/switch-to-configuration switch") + wait_mattermost_up(mutable) + + # AboutLink and HelpLink should be changed, still, and the post should still exist + expect_config(mutable, latest, '.AboutLink == "https://mattermost.com" and .HelpLink == "https://nixos.org/nixos/manual"') + ensure_post(mutable, fail_if_not_found=True) + + mutable.shutdown() + + ## Mostly mutable node tests ## + mostlyMutable.start() + wait_mattermost_up(mostlyMutable) + + # Get the initial config + expect_config(mostlyMutable, esr, '.AboutLink == "https://nixos.org"') + + # No plugins. + expect_plugins(mostlyMutable, 'length == 0') + + # Edit the config and make a post + set_config( + mostlyMutable, + '.SupportSettings.AboutLink = "https://mattermost.com"', + '.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"', + '.PluginSettings.PluginStates."com.mattermost.plugin-todo".Enable = true' + ) + ensure_post(mostlyMutable) + restart_mattermost(mostlyMutable) + + # AboutLink should be overridden by NixOS configuration; HelpLink should be what we set above + expect_config(mostlyMutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual"') + + # Single plugin that's now enabled. + expect_plugins(mostlyMutable, 'length == 1') + + # Post should exist. + ensure_post(mostlyMutable, fail_if_not_found=True) + + # Switch to the latest Mattermost version + mostlyMutable.succeed(f"{mostlyMutableToplevel}/specialisation/latest/bin/switch-to-configuration switch") + wait_mattermost_up(mostlyMutable) + + # AboutLink should be overridden and the post should still exist + expect_config(mostlyMutable, latest, '.AboutLink == "https://nixos.org" and .HelpLink == "https://nixos.org/nixos/manual"') + ensure_post(mostlyMutable, fail_if_not_found=True) + + mostlyMutable.shutdown() + + ## Immutable node tests ## + immutable.start() + wait_mattermost_up(immutable, "Patched Mattermost") + + # Get the initial config + expect_config(immutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"') + + # Edit the config and make a post + set_config( + immutable, + '.SupportSettings.AboutLink = "https://mattermost.com"', + '.SupportSettings.HelpLink = "https://nixos.org/nixos/manual"' + ) + ensure_post(immutable) + restart_mattermost(immutable, "Patched Mattermost") + + # Our edits should be ignored on restart + expect_config(immutable, esr, '.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"') + + # No plugins. + expect_plugins(immutable, 'length == 0') + + # Post should exist. + ensure_post(immutable, fail_if_not_found=True) + + # Switch to the latest Mattermost version + immutable.succeed(f"{immutableToplevel}/specialisation/latest/bin/switch-to-configuration switch") + wait_mattermost_up(immutable) + + # AboutLink and HelpLink should be changed, still, and the post should still exist + expect_config(immutable, latest, '.AboutLink == "https://nixos.org" and .HelpLink == "https://search.nixos.org"') + ensure_post(immutable, fail_if_not_found=True) + + immutable.shutdown() + + ## Environment File node tests ## + environmentFile.start() + wait_mattermost_up(environmentFile) + ensure_post(environmentFile) + + # Settings in the environment file should override settings set otherwise, and the post should exist + expect_config(environmentFile, esr, '.AboutLink == "https://nixos.org"') + ensure_post(environmentFile, fail_if_not_found=True) + + # Switch to the latest Mattermost version + environmentFile.succeed(f"{environmentFileToplevel}/specialisation/latest/bin/switch-to-configuration switch") + wait_mattermost_up(environmentFile) + + # AboutLink should be changed still, and the post should still exist + expect_config(environmentFile, latest, '.AboutLink == "https://nixos.org"') + ensure_post(environmentFile, fail_if_not_found=True) + + environmentFile.shutdown() + + run_mattermost_tests( + "${nodes.mysqlMutable.system.build.toplevel}", + mysqlMutable, + "${nodes.mysqlMostlyMutable.system.build.toplevel}", + mysqlMostlyMutable, + "${nodes.mysqlImmutable.system.build.toplevel}", + mysqlImmutable, + "${nodes.mysqlEnvironmentFile.system.build.toplevel}", + mysqlEnvironmentFile + ) + + run_mattermost_tests( + "${nodes.postgresMutable.system.build.toplevel}", + postgresMutable, + "${nodes.postgresMostlyMutable.system.build.toplevel}", + postgresMostlyMutable, + "${nodes.postgresImmutable.system.build.toplevel}", + postgresImmutable, + "${nodes.postgresEnvironmentFile.system.build.toplevel}", + postgresEnvironmentFile + ) + ''; + } +) diff --git a/nixos/tests/mattermost/test.jpg b/nixos/tests/mattermost/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b1e8e1b4fab90b32630d70a2a39e3100cf23e57 GIT binary patch literal 121879 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 Date: Mon, 30 Dec 2024 19:42:32 -0800 Subject: [PATCH 47/58] manual: add mattermost.chapter.md --- .../doc/manual/configuration/configuration.md | 1 + .../configuration/mattermost.chapter.md | 134 ++++++++++++++++++ nixos/doc/manual/redirects.json | 12 ++ 3 files changed, 147 insertions(+) create mode 100644 nixos/doc/manual/configuration/mattermost.chapter.md diff --git a/nixos/doc/manual/configuration/configuration.md b/nixos/doc/manual/configuration/configuration.md index 4c966f3325b9..fae8874b8323 100644 --- a/nixos/doc/manual/configuration/configuration.md +++ b/nixos/doc/manual/configuration/configuration.md @@ -22,6 +22,7 @@ subversion.chapter.md ```{=include=} chapters profiles.chapter.md +mattermost.chapter.md kubernetes.chapter.md ``` diff --git a/nixos/doc/manual/configuration/mattermost.chapter.md b/nixos/doc/manual/configuration/mattermost.chapter.md new file mode 100644 index 000000000000..f247134ce49a --- /dev/null +++ b/nixos/doc/manual/configuration/mattermost.chapter.md @@ -0,0 +1,134 @@ +# Mattermost {#sec-mattermost} + +The NixOS Mattermost module lets you build [Mattermost](https://mattermost.com) +instances for collaboration over chat, optionally with custom builds of plugins +specific to your instance. + +To enable Mattermost using Postgres, use a config like this: + +```nix +{ + services.mattermost = { + enable = true; + + # You can change this if you are reverse proxying. + host = "0.0.0.0"; + port = 8065; + + # Allow modifications to the config from Mattermost. + mutableConfig = true; + + # Override modifications to the config with your NixOS config. + preferNixConfig = true; + + socket = { + # Enable control with the `mmctl` socket. + enable = true; + + # Exporting the control socket will add `mmctl` to your PATH, and export + # MMCTL_LOCAL_SOCKET_PATH systemwide. Otherwise, you can get the socket + # path out of `config.mattermost.socket.path` and set it manually. + export = true; + }; + + # For example, to disable auto-installation of prepackaged plugins. + settings.PluginSettings.AutomaticPrepackagedPlugins = false; + } +} +``` + +As of NixOS 25.05, Mattermost uses peer authentication with Postgres or +MySQL by default. If you previously used password auth on localhost, +this will automatically be configured if your `stateVersion` is set to at least +`25.05`. + +## Using the Mattermost derivation {#sec-mattermost-derivation} + +The nixpkgs `mattermost` derivation runs the entire test suite during the +`checkPhase`. This test suite is run with a live MySQL and Postgres database +instance in the sandbox. If you are building Mattermost, this can take a while, +especially if it is building on a resource-constrained system. + +The following passthrus are designed to assist with enabling or disabling +the `checkPhase`: + +- `mattermost.withTests` +- `mattermost.withoutTests` + +The default (`mattermost`) is an alias for `mattermost.withTests`. + +## Using Mattermost plugins {#sec-mattermost-plugins} + +You can configure Mattermost plugins by either using prebuilt binaries or by +building your own. We test building and using plugins in the NixOS test suite. + +Mattermost plugins are tarballs containing a system-specific statically linked +Go binary and webapp resources. + +Here is an example with a prebuilt plugin tarball: + +```nix +{ + services.mattermost = { + plugins = with pkgs; [ + /* + * todo + * 0.7.1 + * https://github.com/mattermost/mattermost-plugin-todo/releases/tag/v0.7.1 + */ + (fetchurl { + # Note: Don't unpack the tarball; the NixOS module will repack it for you. + url = "https://github.com/mattermost-community/mattermost-plugin-todo/releases/download/v0.7.1/com.mattermost.plugin-todo-0.7.1.tar.gz"; + hash = "sha256-P+Z66vqE7FRmc2kTZw9FyU5YdLLbVlcJf11QCbfeJ84="; + }) + ]; + }; +} +``` + +Once the plugin is installed and the config rebuilt, you can enable this plugin +in the System Console. + +## Building Mattermost plugins {#sec-mattermost-plugins-build} + +The `mattermost` derivation includes the `buildPlugin` passthru for building +plugins that use the "standard" Mattermost plugin build template at +[mattermost-plugin-demo](https://github.com/mattermost/mattermost-plugin-demo). + +Since this is a "de facto" standard for building Mattermost plugins that makes +assumptions about the build environment, the `buildPlugin` helper tries to fit +these assumptions the best it can. + +Here is how to build the above Todo plugin. Note that we rely on +package-lock.json being assembled correctly, so must use a version where it is! +If there is no lockfile or the lockfile is incorrect, Nix cannot fetch NPM build +and runtime dependencies for a sandbox build. + +```nix +{ + services.mattermost = { + plugins = with pkgs; [ + (mattermost.buildPlugin { + pname = "mattermost-plugin-todo"; + version = "0.8-pre"; + src = fetchFromGitHub { + owner = "mattermost-community"; + repo = "mattermost-plugin-todo"; + # 0.7.1 didn't work, seems to use an older set of node dependencies. + rev = "f25dc91ea401c9f0dcd4abcebaff10eb8b9836e5"; + hash = "sha256-OM+m4rTqVtolvL5tUE8RKfclqzoe0Y38jLU60Pz7+HI="; + }; + vendorHash = "sha256-5KpechSp3z/Nq713PXYruyNxveo6CwrCSKf2JaErbgg="; + npmDepsHash = "sha256-o2UOEkwb8Vx2lDWayNYgng0GXvmS6lp/ExfOq3peyMY="; + extraGoModuleAttrs = { + npmFlags = [ "--legacy-peer-deps" ]; + }; + }) + ]; + }; +} +``` + +See `pkgs/by-name/ma/mattermost/build-plugin.nix` for all the options. +As in the previous example, once the plugin is installed and the config rebuilt, +you can enable this plugin in the System Console. diff --git a/nixos/doc/manual/redirects.json b/nixos/doc/manual/redirects.json index a7ebb49b62b8..443cc445ad69 100644 --- a/nixos/doc/manual/redirects.json +++ b/nixos/doc/manual/redirects.json @@ -47,6 +47,18 @@ "ch-installation": [ "index.html#ch-installation" ], + "sec-mattermost": [ + "index.html#sec-mattermost" + ], + "sec-mattermost-derivation": [ + "index.html#sec-mattermost-derivation" + ], + "sec-mattermost-plugins": [ + "index.html#sec-mattermost-plugins" + ], + "sec-mattermost-plugins-build": [ + "index.html#sec-mattermost-plugins-build" + ], "sec-obtaining": [ "index.html#sec-obtaining" ], From 8c0035ae8f57b65dd055802100044c298439b99d Mon Sep 17 00:00:00 2001 From: Morgan Jones Date: Mon, 11 Nov 2024 21:38:20 -0800 Subject: [PATCH 48/58] release-notes/25.05: add Mattermost details --- nixos/doc/manual/release-notes/rl-2505.section.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 44af73915382..ae954b6750df 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -31,6 +31,18 @@ - `nixos-option` has been rewritten to a Nix expression called by a simple bash script. This lowers our maintenance threshold, makes eval errors less verbose, adds support for flake-based configurations, descending into `attrsOf` and `listOf` submodule options, and `--show-trace`. +- The Mattermost module ({option}`services.mattermost`) and packages (`mattermost` and `mmctl`) have been substantially updated: + - `pkgs.mattermostLatest` is now an option to track the latest (non-prerelease) Mattermost release. We test upgrade migrations from ESR releases (`pkgs.mattermost`) to `pkgs.mattermostLatest`. + - The Mattermost frontend is now built from source and can be overridden. + - Note that the Mattermost derivation containing both the webapp and server is now wrapped to allow them to be built independently, so overrides to both webapp and server look like `mattermost.overrideAttrs (prev: { webapp = prev.webapp.override { ... }; server = prev.server.override { ... }; })` now. + - `services.mattermost.listenAddress` has been split into {option}`services.mattermost.host` and {option}`services.mattermost.port`. If your `listenAddress` contained a port, you will need to edit your configuration. + - Mattermost now supports peer authentication on both MySQL and Postgres database backends. Updating {option}`system.stateVersion` to 25.05 or later will result in peer authentication being used by default if the Mattermost server would otherwise be connecting to localhost. This is the recommended configuration. + - The Mattermost module will produce eval warnings if a database password would end up in the Nix store, and recommend alternatives such as peer authentication or using the environment file. + - Mattermost's entire test suite is now enabled by default, which will extend build time from sources by up to an hour. A `withoutTests` passthru has been added in case you want to skip it. + - We now support `mmctl` for Mattermost administration if both {option}`services.mattermost.socket.enable` and {option}`services.mattermost.socket.export` are set, which export the Mattermost control socket path into the system environment. + - A new `pkgs.mattermost.buildPlugin` function has been added, which allows plugins to be built from source, including webapp frontends with a supported package-lock.json. See the Mattermost NixOS test and [manual](https://nixos.org/manual/nixpkgs/unstable/#sec-mattermost-plugins-build) for an example. + - Note that the Mattermost module will create an account _without_ a well-known UID if the username differs from the default (`mattermost`). If you used Mattermost with a nonstandard username, you may want to review the module changes before upgrading. + ## New Modules {#sec-release-25.05-new-modules} From 33986ca158b28288e84a035d8dfe370afd571fa3 Mon Sep 17 00:00:00 2001 From: Morgan Jones Date: Sun, 19 Jan 2025 12:49:30 -0800 Subject: [PATCH 49/58] {mattermost,mattermostLatest}: fix string escapes --- pkgs/by-name/ma/mattermost/package.nix | 2 +- pkgs/by-name/ma/mattermostLatest/package.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/ma/mattermost/package.nix b/pkgs/by-name/ma/mattermost/package.nix index 55d2cc7c6488..4cea5382b88e 100644 --- a/pkgs/by-name/ma/mattermost/package.nix +++ b/pkgs/by-name/ma/mattermost/package.nix @@ -18,7 +18,7 @@ # the version regex here as well. # # Ensure you also check ../mattermostLatest/package.nix. - regex = "^v(9\.11\.[0-9]+)$"; + regex = "^v(9\\.11\\.[0-9]+)$"; version = "9.11.7"; srcHash = "sha256-KeGpYy3jr7/B2mtBk9em2MXJBJR2+Wajmvtz/yT4SG8="; vendorHash = "sha256-alLPBfnA1o6bUUgPRqvYW/98UKR9wltmFTzKIGtVEm4="; diff --git a/pkgs/by-name/ma/mattermostLatest/package.nix b/pkgs/by-name/ma/mattermostLatest/package.nix index 6fe04afdd92e..3b3b2674c756 100644 --- a/pkgs/by-name/ma/mattermostLatest/package.nix +++ b/pkgs/by-name/ma/mattermostLatest/package.nix @@ -10,7 +10,7 @@ mattermost.override { # See https://docs.mattermost.com/about/mattermost-server-releases.html # and make sure the version regex is up to date here. # Ensure you also check ../mattermost/package.nix for ESR releases. - regex = "^v(10\.[0-9]+\.[0-9]+)$"; + regex = "^v(10\\.[0-9]+\\.[0-9]+)$"; version = "10.4.1"; srcHash = "sha256-e7uT30tWhJpEQzlcDUY2huFcupDbe4l8B19Dgub2pg0="; vendorHash = "sha256-AcemUxcBoytE/ZoXqaIlxkzAnmGV/C1laDqziMuE+XE="; From 3b6f658130e5ed7a027593a6f24c1c1c700f2b89 Mon Sep 17 00:00:00 2001 From: Yureka Date: Mon, 20 Jan 2025 08:29:57 +0100 Subject: [PATCH 50/58] init-script-builder: fix build (#375160) Change-Id: I244160844aad5fcfcab323dd721cfd87e4b8ddc0 --- .../system/boot/loader/init-script/init-script-builder.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/nixos/modules/system/boot/loader/init-script/init-script-builder.sh b/nixos/modules/system/boot/loader/init-script/init-script-builder.sh index 60b9fe901db0..6c21dfaac09d 100644 --- a/nixos/modules/system/boot/loader/init-script/init-script-builder.sh +++ b/nixos/modules/system/boot/loader/init-script/init-script-builder.sh @@ -27,9 +27,6 @@ tmpOther="$targetOther.tmp" configurationCounter=0 -numAlienEntries=`cat < Date: Mon, 20 Jan 2025 08:26:09 +0100 Subject: [PATCH 51/58] Revert "uhd: pin Boost 1.86" Patch for 1.87 was merged in eede7811b4b026c75ce3b2f91ed20bf26019261e. --- pkgs/applications/radio/uhd/default.nix | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkgs/applications/radio/uhd/default.nix b/pkgs/applications/radio/uhd/default.nix index 9b05d201f933..6ff0c16a3106 100644 --- a/pkgs/applications/radio/uhd/default.nix +++ b/pkgs/applications/radio/uhd/default.nix @@ -8,8 +8,7 @@ cmake, pkg-config, # See https://files.ettus.com/manual_archive/v3.15.0.0/html/page_build_guide.html for dependencies explanations - # Pin Boost 1.86 due to use of boost::asio::io_service. - boost186, + boost, ncurses, enableCApi ? true, enablePythonApi ? true, @@ -165,7 +164,7 @@ stdenv.mkDerivation (finalAttrs: { buildInputs = finalAttrs.pythonPath ++ [ - boost186 + boost libusb1 ] ++ optionals (enableExamples) [ From 397e5bb5a79f85c86a4f5dcd3382d205aff3bec3 Mon Sep 17 00:00:00 2001 From: Seth Flynn Date: Mon, 20 Jan 2025 02:32:47 -0500 Subject: [PATCH 52/58] rustc: mark broken for LLVM stdenv --- pkgs/development/compilers/rust/rustc.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkgs/development/compilers/rust/rustc.nix b/pkgs/development/compilers/rust/rustc.nix index af287fcc9079..d7a1ee625f9c 100644 --- a/pkgs/development/compilers/rust/rustc.nix +++ b/pkgs/development/compilers/rust/rustc.nix @@ -421,5 +421,10 @@ stdenv.mkDerivation (finalAttrs: { # If rustc can't target a platform, we also can't build rustc for # that platform. badPlatforms = rustc.badTargetPlatforms; + # Builds, but can't actually compile anything + # https://github.com/NixOS/nixpkgs/issues/311930 + # https://github.com/rust-lang/rust/issues/55120 + # https://github.com/rust-lang/rust/issues/82521 + broken = stdenv.hostPlatform.useLLVM; }; }) From 8e56483d50032f842e3ac6c4e57c732b9638b261 Mon Sep 17 00:00:00 2001 From: Gaetan Lepage Date: Mon, 20 Jan 2025 08:43:57 +0100 Subject: [PATCH 53/58] python312Packages.timm: 1.0.13 -> 1.0.14 Diff: https://github.com/huggingface/pytorch-image-models/compare/refs/tags/v1.0.13...v1.0.14 Changelog: https://github.com/huggingface/pytorch-image-models/blob/v1.0.14/README.md#whats-new --- pkgs/development/python-modules/timm/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/development/python-modules/timm/default.nix b/pkgs/development/python-modules/timm/default.nix index 8dd7cd7ebdd1..a70d1f503723 100644 --- a/pkgs/development/python-modules/timm/default.nix +++ b/pkgs/development/python-modules/timm/default.nix @@ -21,14 +21,14 @@ buildPythonPackage rec { pname = "timm"; - version = "1.0.13"; + version = "1.0.14"; pyproject = true; src = fetchFromGitHub { owner = "huggingface"; repo = "pytorch-image-models"; tag = "v${version}"; - hash = "sha256-VRQerCaTiOvS3Mm+Fksua7KUhNcH1Zxc2+4jaSbVj+c="; + hash = "sha256-mQd4xsKuAKj77lG6r14iHrkaBclRmBwICXuHs7pQoGI="; }; build-system = [ pdm-backend ]; From 8e7b1073fde774c48cb9d38076081a48d4ca7a58 Mon Sep 17 00:00:00 2001 From: Vincent Laporte Date: Mon, 20 Jan 2025 08:36:53 +0100 Subject: [PATCH 54/58] ocamlPackages.elpi: use correct version information --- pkgs/development/ocaml-modules/elpi/default.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkgs/development/ocaml-modules/elpi/default.nix b/pkgs/development/ocaml-modules/elpi/default.nix index 69af0157d5d3..a9dc8597b8dd 100644 --- a/pkgs/development/ocaml-modules/elpi/default.nix +++ b/pkgs/development/ocaml-modules/elpi/default.nix @@ -36,10 +36,11 @@ let fetched = coqPackages.metaFetch ({ else "elpi-v${v}.tbz"; location = { domain = "github.com"; owner = "LPCIC"; repo = "elpi"; }; }) version; -in -buildDunePackage { +in let inherit (fetched) version; +in buildDunePackage { pname = "elpi"; - inherit (fetched) version src; + inherit version; + inherit (fetched) src; patches = lib.optional (version == "1.16.5") ./atd_2_10.patch; From ec4b54f3d04a825d311c0b69926eaa8a3a213c02 Mon Sep 17 00:00:00 2001 From: Benedikt Ritter Date: Mon, 20 Jan 2025 09:00:19 +0100 Subject: [PATCH 55/58] nextcloud: Add britter as maintainer --- pkgs/servers/nextcloud/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/servers/nextcloud/default.nix b/pkgs/servers/nextcloud/default.nix index 624212f6efed..a06f49658769 100644 --- a/pkgs/servers/nextcloud/default.nix +++ b/pkgs/servers/nextcloud/default.nix @@ -48,6 +48,7 @@ let bachp globin ma27 + britter ]; license = lib.licenses.agpl3Plus; platforms = lib.platforms.linux; From d4c0bd6dc5b929133e33e21b096b9737cca58031 Mon Sep 17 00:00:00 2001 From: FliegendeWurst Date: Sun, 19 Jan 2025 12:21:41 +0100 Subject: [PATCH 56/58] wf-config: fix and enable strictDeps --- pkgs/applications/window-managers/wayfire/wf-config.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/applications/window-managers/wayfire/wf-config.nix b/pkgs/applications/window-managers/wayfire/wf-config.nix index 8ebbd647bcd7..80511e5abb67 100644 --- a/pkgs/applications/window-managers/wayfire/wf-config.nix +++ b/pkgs/applications/window-managers/wayfire/wf-config.nix @@ -40,11 +40,15 @@ stdenv.mkDerivation (finalAttrs: { nativeCheckInputs = [ cmake + ]; + checkInputs = [ doctest ]; # CMake is just used for finding doctest. dontUseCmakeConfigure = true; + strictDeps = true; + mesonFlags = [ (lib.mesonEnable "tests" (stdenv.buildPlatform.canExecute stdenv.hostPlatform)) ]; From db8996f0809493993a2ddb0f0000ba8af8597eaa Mon Sep 17 00:00:00 2001 From: Louis Thevenet Date: Mon, 20 Jan 2025 09:33:54 +0100 Subject: [PATCH 57/58] television: 0.9.2 -> 0.9.3 --- pkgs/by-name/te/television/package.nix | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pkgs/by-name/te/television/package.nix b/pkgs/by-name/te/television/package.nix index 52453f93333b..3c9af991b718 100644 --- a/pkgs/by-name/te/television/package.nix +++ b/pkgs/by-name/te/television/package.nix @@ -8,16 +8,16 @@ }: rustPlatform.buildRustPackage rec { pname = "television"; - version = "0.9.2"; + version = "0.9.3"; src = fetchFromGitHub { owner = "alexpasmantier"; repo = "television"; tag = version; - hash = "sha256-XMANif4WbI+imSYeQRlvZJYjtaVbKrD4wVx2mQ1HYHg="; + hash = "sha256-0VnDgDLsPmNaY1sjw891hm65TsE3HH9KBkkgp0TFQKg="; }; - cargoHash = "sha256-IXtmQdDO3OHBZALWQKhJVgEimvuNyAj0/7aUlnL395M="; + cargoHash = "sha256-WtB1rmgOfAnZ9OGJ8M5s5NqMm24s8gcPzlu14f2mTrE="; passthru = { tests.version = testers.testVersion { @@ -28,15 +28,13 @@ rustPlatform.buildRustPackage rec { }; meta = { - description = "Television is a blazingly fast general purpose fuzzy finder"; - + description = "Blazingly fast general purpose fuzzy finder TUI"; longDescription = '' - Television is a blazingly fast general purpose fuzzy finder TUI written - in Rust. It is inspired by the neovim telescope plugin and is designed - to be fast, efficient, simple to use and easily extensible. It is built - on top of tokio, ratatui and the nucleo matcher used by the helix editor. + Television is a fast and versatile fuzzy finder TUI. + It lets you quickly search through any kind of data source (files, git + repositories, environment variables, docker images, you name it) using a + fuzzy matching algorithm and is designed to be easily extensible. ''; - homepage = "https://github.com/alexpasmantier/television"; changelog = "https://github.com/alexpasmantier/television/releases/tag/${version}"; license = lib.licenses.mit; From 3e47905de2684f6046a8ecca1cd6898971259a4c Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 20 Jan 2025 00:54:25 +0000 Subject: [PATCH 58/58] fzf: 0.57.0 -> 0.58.0 --- pkgs/by-name/fz/fzf/package.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/by-name/fz/fzf/package.nix b/pkgs/by-name/fz/fzf/package.nix index a0a218db10bd..15e9a0fc6289 100644 --- a/pkgs/by-name/fz/fzf/package.nix +++ b/pkgs/by-name/fz/fzf/package.nix @@ -11,16 +11,16 @@ buildGoModule rec { pname = "fzf"; - version = "0.57.0"; + version = "0.58.0"; src = fetchFromGitHub { owner = "junegunn"; repo = "fzf"; rev = "v${version}"; - hash = "sha256-WEdCa6Krj+VicB1vxWzyY1rCHvmaL4t2njhhjq0Bppw="; + hash = "sha256-0HlmUwQFitd1He+F16JiwDcP0t9Bfo0sAm8owlb/Ygs="; }; - vendorHash = "sha256-utHQzXjtdnshUsYDQEQY2qoQGZsnfXXPj3A9VsDj0vQ="; + vendorHash = "sha256-rUG926YdBTZyJfpTG0kXr2zo+yw1eNEUlolS6Q7C+ng="; env.CGO_ENABLED = 0;