Skip to content

Commit

Permalink
lib: add collectFiles and collectFilesAt
Browse files Browse the repository at this point in the history
These are lib functions that recursively read a directory, and return
files in the format expected by `files`/`symlinks`. This makes it
possible to, for example, link all mods from a modpack, and still
include additional mods/configs.
  • Loading branch information
Misterio77 committed Dec 26, 2024
1 parent 2bc6a3c commit 5620998
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 18 deletions.
61 changes: 43 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,57 +146,82 @@ in
symlinks = {
"mods" = "${modpack}/mods";
};
files = {
"config" = "${modpack}/config";
"config/mod1.yml" = "${modpack}/config/mod1.yml";
"config/mod2.conf" = "${modpack}/config/mod2.conf";
# You can add files not on the modpack, of course
"config/server-specific.conf".value = {
example = "foo-bar";
};
};
};
}
```

This will symlink the modpack's final `mods` directory into the server's `mods` directory. You can also do this for `config`, or any files in the modpack you're interested in, in a granular way.
This will symlink the modpack's final `mods` directory into the server's `mods` directory, and copy the specified config files into `config`. You can also do this for any files in the modpack you're interested in, in a granular way.

**Note**: Be sure to use a stable URL (e.g. a git tag/commit) to the manifest, as it changing will cause the derivation to generate a different hash, breaking the build until you change it.

The built modpack also exports a `manifest` attribute, that allows you to get any information from its `pack.toml` file, such as the MC or Modloader version. You can, this way, always sync the server's version with the one the modpack recommends:
Adding config files one by-one is boring. Trying to include an additional mod will also fail, as `mods` is read-only and symlinked as is. To solve these issues, this flake provides a `collectFilesAt` function, that recursively collects every file on the given directory (e.g. `config`), and returns an attribute set in the format `symlinks`/`files` expects. For example:

```nix
{ inputs, ... }:
let
inherit (inputs.nix-minecraft.lib) collectFilesAt;
modpack = pkgs.fetchPackwizModpack {
url = "https://github.com/Misterio77/Modpack/raw/0.2.9/pack.toml";
packHash = "sha256-L5RiSktqtSQBDecVfGj1iDaXV+E90zrNEcf4jtsg+wk=";
};
mcVersion = modpack.manifest.versions.minecraft;
fabricVersion = modpack.manifest.versions.fabric;
serverVersion = lib.replaceStrings [ "." ] [ "_" ] "fabric-${mcVersion}";
in
{
services.minecraft-servers.servers.cool-modpack = {
enable = true;
package = pkgs.fabricServers.${serverVersion}.override { loaderVersion = fabricVersion; };
symlinks = {
"mods" = "${modpack}/mods";
package = pkgs.fabricServers.fabric-1_18_2-0_14_9;
symlinks = collectFilesAt modpack "mods" // {
"mods/FabricProxy-lite.jar" = pkgs.fetchurl rec {
pname = "FabricProxy-Lite";
version = "1.1.6";
url = "https://cdn.modrinth.com/data/8dI2tmqs/versions/v${version}/${pname}-${version}.jar";
hash = "sha256-U+nXvILXlYdx0vgomVDkKxj0dGCtw60qW22EK4FhAJk=";
};
};
files = collectFilesAt modpack "config" // {
"config/server-specific.conf".value = {
example = "foo-bar";
};
};
};
}
```

**Note**: Using `manifest`, by default, will cause [IFD](https://nixos.wiki/wiki/Import_From_Derivation). If you want to avoid IFD while still having access to `manifest`, simply pass a `manifestHash` to the `fetchPackwizModpack` function, it will then fetch the manifest through `builtins.fetchurl`.
**Note**: Calling `collectFilesAt` on a derivation (e.g. the modpack) will cause [IFD](https://nixos.wiki/wiki/Import_From_Derivation).

Additionally, you can override/add files (e.g. server-specific mods) on the pack through `addFiles`. For example:
The built modpack also exports a `manifest` attribute, that allows you to get any information from its `pack.toml` file, such as the MC or Modloader version. You can, this way, always sync the server's version with the one the modpack recommends:

```nix
let
modpack = (pkgs.fetchPackwizModpack {
modpack = pkgs.fetchPackwizModpack {
url = "https://github.com/Misterio77/Modpack/raw/0.2.9/pack.toml";
packHash = "sha256-L5RiSktqtSQBDecVfGj1iDaXV+E90zrNEcf4jtsg+wk=";
}).addFiles {
"mods/FabricProxy-lite.jar" = pkgs.fetchurl rec {
pname = "FabricProxy-Lite";
version = "1.1.6";
url = "https://cdn.modrinth.com/data/8dI2tmqs/versions/v${version}/${pname}-${version}.jar";
hash = "sha256-U+nXvILXlYdx0vgomVDkKxj0dGCtw60qW22EK4FhAJk=";
};
};
mcVersion = modpack.manifest.versions.minecraft;
fabricVersion = modpack.manifest.versions.fabric;
serverVersion = lib.replaceStrings [ "." ] [ "_" ] "fabric-${mcVersion}";
in
{
services.minecraft-servers.servers.cool-modpack = {
enable = true;
package = pkgs.fabricServers.${serverVersion}.override { loaderVersion = fabricVersion; };
symlinks = {
"mods" = "${modpack}/mods";
};
};
}
```

**Note**: Using `manifest`, by default, will cause [IFD](https://nixos.wiki/wiki/Import_From_Derivation). If you want to avoid IFD while still having access to `manifest`, simply pass a `manifestHash` to the `fetchPackwizModpack` function, it will then fetch the manifest through `builtins.fetchurl`.

### Others

All of these packages are also available under `packages`, not just `legacyPackages`.
Expand Down
15 changes: 15 additions & 0 deletions lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ let
stringToCharacters
take
versionOlder
nameValuePair
;
inherit (builtins)
match
Expand Down Expand Up @@ -76,4 +77,18 @@ rec {
files = filterAttrs seive (readDir dirPath);
in
filterAttrs (n: v: v != { }) (mapAttrs' collect files);

# Same as collectFiles, but only gathers files from a specific subdirectory
# (e.g. "config")
collectFilesAt = path: subdir: mapAttrs' (n: nameValuePair ("${subdir}/${n}")) (collectFiles "${path}/${subdir}");

# Get all files from a path (e.g. a modpack derivation) and return them in the
# format expected by the files/symlinks module options.
collectFiles = let
mapListToAttrs = fn: fv: list:
lib.listToAttrs (map (x: nameValuePair (fn x) (fv x)) list);
in path:
mapListToAttrs
(x: builtins.unsafeDiscardStringContext (lib.removePrefix "${path}/" x))
(lib.id) (lib.filesystem.listFilesRecursive "${path}");
})

0 comments on commit 5620998

Please sign in to comment.