Updating attributes in a set in the same scope

I am currently writing a module to easily add plugins to a minecraft server, specifically plugins compatible with the bukkit api.
to do that I basically just need to add jar files and config files in the $dataDir/plugins directory of the minecraft server.

I basically start a systemd service for every plugin that then symlinks the proper package and config file to it’s location in the plugin directory.

Now I need to delete all jar files that aren’t currently being used, so that I can actually disable plugins as well.
My idea was to also start a service that before every other service just removes every jar file that doesn’t correspond to one of the prior described services.
The issue for me is, when I set the services with

systemd.services = mapAttrs' (n: v: nameValuePair "bukkit-plugin-${n}" (mkService n v)) cfg.plugins;

I can’t then directly after that add that jar remover service to the set.

error: attribute 'systemd.services.bukkit-plugins' at /home/kaine/git/nur-packages/modules/bukkit-plugins/default.nix:105:5 already defined at /home/kaine/git/nur-packages/modules/bukkit-plugins/default.nix:103:5
(use '--show-trace' to show detailed location information)

I assume this would update perfectly if it wasn’t in the same scope?
Maybe I’m going about this in a completely weird way…
Thank you for any help or recommendations!

I feel like there might be a better solution for your use case, but to the point:

  1. The simplest way is to use the update operator:
config = mkIf cfg.enable {
  systemd.services = (mapAttrs' (n: v: nameValuePair "bukkit-plugin-${n}" (mkService n v)) cfg.plugins) // {
    bukkit-plugins = {
      description = "service to prepare the plugins directory for other bukkit plugins";
      wantedBy = [ "multi-user.target" ];
      script =
        let
          findExceptions = concatStringsSep " " mapAttrsToList (n: v: "! -name ${n}.jar") cfg.plugins;
        in
        ''
          # remove old plugins before starting new plugins
          find . ${findExceptions} -maxdepth 1 -name "*.jar" -type f -delete
        '';
    };
  };
};
  1. In general, you can use mkMerge to make it seem like multiple different modules:
config = mkIf cfg.enable (mkMerge [
  {
    systemd.services = mapAttrs' (n: v: nameValuePair "bukkit-plugin-${n}" (mkService n v)) cfg.plugins;
  }

  {
    systemd.services.bukkit-plugins = {
      description = "service to prepare the plugins directory for other bukkit plugins";
      wantedBy = [ "multi-user.target" ];
      script =
        let
          findExceptions = concatStringsSep " " mapAttrsToList (n: v: "! -name ${n}.jar") cfg.plugins;
        in
        ''
          # remove old plugins before starting new plugins
          find . ${findExceptions} -maxdepth 1 -name "*.jar" -type f -delete
        '';
    };
  }
]);
1 Like

ah thank you!!

hope this isn’t too off-topic now, but maybe something like buildEnv would be more sensible since that’s all about symlinking a bunch of stuff and then symlinking that to the plugins directory?

only issue I see with that is plugins who want to write to the plugins directory. maybe that can be configured or patched out for the relevant plugins.