From 0945875a2a20de314093b0f9d4d5448e9b4fdccb Mon Sep 17 00:00:00 2001
From: nikp123 <nikp123@e.email>
Date: Fri, 9 Jun 2023 22:32:11 +0200
Subject: [PATCH] boxxy: add module (#4075)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* boxxy: add module

 * boxxy: added nikp123 to maintainers list

* boxxy: use mkPackageOption instead for the package

Co-authored-by: Naïm Favier <n@monade.li>

* boxxy: use yaml generator instead of json

Co-authored-by: Naïm Favier <n@monade.li>

* boxxy: various fixes

* boxxy: various fixes (part 2)

* boxxy: various fixes (part 3)

* boxxy: various fixes (part 4)

forgot to run ./format, whoops

* boxxy: use literalExpression for the rewrite example

Co-authored-by: Naïm Favier <n@monade.li>

* boxxy: add news entry

---------

Co-authored-by: Naïm Favier <n@monade.li>
---
 modules/lib/maintainers.nix                   |   6 +
 modules/misc/news.nix                         |   8 ++
 modules/modules.nix                           |   1 +
 modules/programs/boxxy.nix                    | 110 ++++++++++++++++++
 tests/default.nix                             |   1 +
 tests/modules/programs/boxxy/default.nix      |   4 +
 .../modules/programs/boxxy/empty-settings.nix |  15 +++
 .../modules/programs/boxxy/example-boxxy.yaml |  12 ++
 .../programs/boxxy/example-settings.nix       |  26 +++++
 9 files changed, 183 insertions(+)
 create mode 100644 modules/programs/boxxy.nix
 create mode 100644 tests/modules/programs/boxxy/default.nix
 create mode 100644 tests/modules/programs/boxxy/empty-settings.nix
 create mode 100644 tests/modules/programs/boxxy/example-boxxy.yaml
 create mode 100644 tests/modules/programs/boxxy/example-settings.nix

diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix
index 2ad490f1..6645e7c2 100644
--- a/modules/lib/maintainers.nix
+++ b/modules/lib/maintainers.nix
@@ -159,6 +159,12 @@
     github = "mifom";
     githubId = 23462908;
   };
+  nikp123 = {
+    name = "nikp123";
+    email = "nikp123@users.noreply.github.com";
+    github = "nikp123";
+    githubId = 4696350;
+  };
   nilp0inter = {
     name = "Roberto Abdelkader Martínez Pérez";
     email = "robertomartinezp@gmail.com";
diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 3c665eb7..1685b4ed 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -1062,6 +1062,14 @@ in
           A new module is available: 'programs.imv'.
         '';
       }
+
+      {
+        time = "2023-06-09T19:13:39+00:00";
+        condition = hostPlatform.isLinux;
+        message = ''
+          A new module is available: 'programs.boxxy'.
+        '';
+      }
     ];
   };
 }
diff --git a/modules/modules.nix b/modules/modules.nix
index 0ee8ee54..736922d5 100644
--- a/modules/modules.nix
+++ b/modules/modules.nix
@@ -60,6 +60,7 @@ let
     ./programs/beets.nix
     ./programs/borgmatic.nix
     ./programs/bottom.nix
+    ./programs/boxxy.nix
     ./programs/broot.nix
     ./programs/browserpass.nix
     ./programs/btop.nix
diff --git a/modules/programs/boxxy.nix b/modules/programs/boxxy.nix
new file mode 100644
index 00000000..566a11e7
--- /dev/null
+++ b/modules/programs/boxxy.nix
@@ -0,0 +1,110 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.programs.boxxy;
+
+  configPath = "${config.xdg.configHome}/boxxy/boxxy.yaml";
+  settingsFormat = pkgs.formats.yaml { };
+
+  boxxyRulesOpts = types.submodule {
+    freeformType = settingsFormat.type;
+
+    options = {
+      name = mkOption {
+        type = types.str;
+        description = ''
+          Unique identifier of the boxxy rule. This can be any single-line string.
+        '';
+      };
+
+      target = mkOption {
+        type = types.str;
+        default = "";
+        example = "~/.ssh";
+        description = ''
+          What directory/file to redirect.
+        '';
+      };
+
+      rewrite = mkOption {
+        type = types.str;
+        default = "";
+        example = literalExpression ''"''${config.xdg.configHome}/ssh"'';
+        description = ''
+          Where that file/directory should be rewritten to.
+        '';
+      };
+
+      mode = mkOption {
+        type = types.enum [ "file" "directory" ];
+        default = "directory";
+        description = ''
+          Does the current path redirect a file or a directory?
+        '';
+      };
+
+      only = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = literalExpression ''
+          [
+            "bash"
+            "/usr/bin/sh"
+          ]
+        '';
+        description = ''
+          Apply redirection ONLY to specified executable names.
+        '';
+      };
+
+      context = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "/home/example/Projects/my-project" ];
+        description = ''
+          Apply redirection ONLY when in a certain directory.
+        '';
+      };
+
+      env = mkOption {
+        type = types.attrsOf types.str;
+        default = { };
+        example = literalExpression ''
+          {
+            MY_ENV_VAR = "my_env_var_value";
+          }
+        '';
+        description = ''
+          Give certain environment variables for said match.
+        '';
+      };
+    };
+  };
+in {
+  options.programs.boxxy = {
+    enable = mkEnableOption "boxxy: Boxes in badly behaving applications";
+
+    package = mkPackageOption pkgs "boxxy" { };
+
+    rules = mkOption {
+      type = types.listOf boxxyRulesOpts;
+      default = [ ];
+      description = "List of boxxy rules";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions =
+      [ (hm.assertions.assertPlatform "programs.boxxy" pkgs platforms.linux) ];
+
+    home.file = mkIf (cfg.rules != [ ]) {
+      "${configPath}".source =
+        settingsFormat.generate "boxxy-config.yaml" { rules = cfg.rules; };
+    };
+
+    home.packages = [ cfg.package ];
+  };
+
+  meta.maintainers = with lib.hm.maintainers; [ nikp123 ];
+}
+
diff --git a/tests/default.nix b/tests/default.nix
index 6eab6179..d24ef824 100644
--- a/tests/default.nix
+++ b/tests/default.nix
@@ -156,6 +156,7 @@ import nmt {
     ./modules/programs/autorandr
     ./modules/programs/beets  # One test relies on services.mpd
     ./modules/programs/borgmatic
+    ./modules/programs/boxxy
     ./modules/programs/browserpass # TODO re-enable on Darwin when https://github.com/NixOS/nixpkgs/pull/236258#issuecomment-1583450593 is fixed
     ./modules/programs/firefox
     ./modules/programs/foot
diff --git a/tests/modules/programs/boxxy/default.nix b/tests/modules/programs/boxxy/default.nix
new file mode 100644
index 00000000..52ebcacc
--- /dev/null
+++ b/tests/modules/programs/boxxy/default.nix
@@ -0,0 +1,4 @@
+{
+  boxxy-empty-settings = ./empty-settings.nix;
+  boxxy-example-settings = ./example-settings.nix;
+}
diff --git a/tests/modules/programs/boxxy/empty-settings.nix b/tests/modules/programs/boxxy/empty-settings.nix
new file mode 100644
index 00000000..3a34cd5c
--- /dev/null
+++ b/tests/modules/programs/boxxy/empty-settings.nix
@@ -0,0 +1,15 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  config = {
+    programs.boxxy.enable = true;
+
+    test.stubs.boxxy = { };
+
+    nmt.script = ''
+      assertPathNotExists home-files/.config/boxxy
+    '';
+  };
+}
diff --git a/tests/modules/programs/boxxy/example-boxxy.yaml b/tests/modules/programs/boxxy/example-boxxy.yaml
new file mode 100644
index 00000000..edd7aeda
--- /dev/null
+++ b/tests/modules/programs/boxxy/example-boxxy.yaml
@@ -0,0 +1,12 @@
+rules:
+- context:
+  - /home/test_user/your_project_repo
+  env:
+    ENVIRONMENT_THING: some value
+  mode: directory
+  name: example rule
+  only:
+  - arduino
+  - Arduino
+  rewrite: ~/.local/share/boxxy
+  target: ~/Arduino
diff --git a/tests/modules/programs/boxxy/example-settings.nix b/tests/modules/programs/boxxy/example-settings.nix
new file mode 100644
index 00000000..7ecec416
--- /dev/null
+++ b/tests/modules/programs/boxxy/example-settings.nix
@@ -0,0 +1,26 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  config = {
+    programs.boxxy.enable = true;
+    programs.boxxy.rules = [{
+      name = "example rule";
+      target = "~/Arduino";
+      rewrite = "~/.local/share/boxxy";
+      mode = "directory";
+      only = [ "arduino" "Arduino" ];
+      env = { "ENVIRONMENT_THING" = "some value"; };
+      context = [ "/home/test_user/your_project_repo" ];
+    }];
+
+    test.stubs.boxxy = { };
+
+    nmt.script = ''
+      boxxyyaml=home-files/.config/boxxy/boxxy.yaml
+      assertFileExists $boxxyyaml
+      assertFileContent $boxxyyaml ${./example-boxxy.yaml}
+    '';
+  };
+}