summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorseth <[email protected]>2023-05-11 02:02:39 -0400
committerseth <[email protected]>2023-05-11 02:03:53 -0400
commita0c9b2378a0d1b3e57fda1d377b9914e3bc141b6 (patch)
treed0ad503a82749414e93ab3cc0874d8f2e1f69dda
feat: initial commit
-rw-r--r--.gitignore5
-rw-r--r--LICENSE21
-rw-r--r--README.md99
-rw-r--r--flake.nix5
-rw-r--r--lib/default.nix123
5 files changed, 253 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6e42468
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+# nix build artifacts
+result
+
+# cached devShells
+.direnv
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..cdf9e16
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 seth
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..703985f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,99 @@
+# packwiz2nix
+
+packwiz2nix brings all of the benefits of Nix to [packwiz](https://packwiz.infra.link/), helping you create
+[fixed-output derivations](https://nixos.org/manual/nix/stable/language/advanced-attributes.html#adv-attr-outputHash) from
+your already existing packwiz modpack!
+
+## Getting started
+
+### For users
+
+It is recommended to use [misterio77's](https://github.com/Misterio77) [nix-minecraft](https://github.com/misterio77/nix-minecraft)
+module as it allows you to symlink packages into a minecraft server's directory.
+
+There is a convenience function called `mkModLinks` that can automate the creation of symlinks for a server like so:
+
+```nix
+{
+ nix-minecraft,
+ packwiz2nix,
+ pkgs,
+ yourModpack,
+ ...
+}: let
+ inherit (packwiz2nix.lib) mkPackwizPackages mkModLinks;
+ # replace "/checksums.json" with the path to the modpack's checksums file
+ mods = mkPackwizPackages pkgs (yourModpack + "/checksums.json");
+in {
+ imports = [
+ nix-minecraft.nixosModules.minecraft-servers
+ ];
+
+ nixpkgs.overlays = [nix-minecraft.overlay];
+
+ services.minecraft-servers = {
+ enable = true;
+ eula = true;
+
+ servers.my_server = {
+ enable = true;
+ package = pkgs.quiltServers.quilt-1_19_4-0_18_10;
+ symlinks = mkModLinks mods;
+ };
+ };
+}
+```
+
+### For modpack developers
+
+packwiz2nix is quick to set up, all you have to do is add this to the `apps` attribute of a flake:
+
+```nix
+{
+ inputs = {
+ nixpkgs.url = "nixpkgs/nixos-unstable";
+ flake-utils.url = "github:numtide/flake-utils";
+ packwiz2nix.url = "github:getchoo/packwiz2nix";
+ };
+
+ outputs = {
+ nixpkgs,
+ flake-utils,
+ packwiz2nix,
+ ...
+ }:
+ flake-utils.lib.eachDefaultSystem (system: let
+ pkgs = import nixpkgs {inherit system;};
+ in {
+ apps = {
+ # replace ./mods with the path to your .pw.toml files
+ generate-checksums = packwiz2nix.lib.mkChecksumsApp pkgs ./mods;
+ };
+ });
+}
+```
+
+An example of this can be found in my [personal modpack](https://github.com/getchoo/modpack/blob/main/flake.nix)
+
+## Gotchas!
+
+There are two main things you should keep in mind with this project currently:
+
+- No Curseforge support
+
+ - Packwiz does not keep the download URL to mods from Curseforge in it's TOML files,
+ which is not acceptable in the current method used to generate checksums and create
+ the final derivations for mods. This may be changed in the future
+
+ - This is the biggest concern as it affects end users the most
+
+- Checksums must be generated (**modpack developers, make sure you read this**)
+ - Packwiz uses SHA1 to verify mod files, which fetchers in nix such as `builtins.fetchurl`
+ and `pkgs.fetchurl` do not support. This prevents us from using them, and requires a separate
+ checksum file (using SHA256) to be generated and updated along with the modpack. I don't see
+ how this can be resolved in the foreseeable future unless SHA256 is adopted by Packwiz.
+
+## Related Projects
+
+- [misterio77/nix-minecraft](https://github.com/misterio77/nix-minecraft)
+- [nix-community/mineflake](https://github.com/nix-community/mineflake)
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..bc1640d
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,5 @@
+{
+ description = "a tool for generating packages from packwiz modpacks";
+
+ outputs = _: {lib = import ./lib;};
+}
diff --git a/lib/default.nix b/lib/default.nix
new file mode 100644
index 0000000..8086059
--- /dev/null
+++ b/lib/default.nix
@@ -0,0 +1,123 @@
+let
+ inherit
+ (builtins)
+ attrNames
+ hashFile
+ fetchurl
+ fromJSON
+ listToAttrs
+ mapAttrs
+ readDir
+ readFile
+ replaceStrings
+ toFile
+ toJSON
+ ;
+
+ # loads data from a toml json given
+ # the directory (dir) and filename (name)
+ # string -> string -> attrset
+ fromMod = dir: name: fromTOML (readFile "${dir}/${name}");
+
+ # replaces `.pw.toml` extensions with `.jar`
+ # to correct the store paths of jarfiles
+ # string -> string
+ fixupName = replaceStrings [".pw.toml"] [".jar"];
+
+ # *pkgs*.fetchurl wrapper that downloads a
+ # jarfile mod. pkgs.fetchurl is used over builtins
+ # here since we have a checksum and can take advantage
+ # of fixed output derivations
+ # attrset -> string -> attrset -> store path
+ mkMod = pkgs: name: mod:
+ pkgs.fetchurl {
+ name = fixupName name;
+ inherit (mod) url sha256;
+ };
+
+ # maps each mod in our checksums.json format
+ # to the store path of a fixed output derivation
+ # attrset -> attrset
+ genMods = pkgs:
+ mapAttrs (mkMod pkgs);
+
+ # this is probably what you're looking for if
+ # you're a developer trying to use this in your modpack.
+ # this is where you create a checksums file for end users
+ # to put into mkPackwizPackages, so make sure you keep it up to
+ # date!
+ #
+ # `dir` is a path to the folder containing your .pw.toml files
+ # files for mods. make sure they are the only files in the folder
+ #
+ # path -> file
+ mkChecksums = dir: let
+ mods = readDir dir;
+
+ getChecksum = name: url:
+ hashFile "sha256" (fetchurl {
+ name = fixupName name;
+ inherit url;
+ });
+
+ toWrite =
+ toJSON
+ (mapAttrs (mod: _: let
+ data = fromMod dir mod;
+ in {
+ inherit (data.download) url;
+ sha256 = getChecksum mod data.download.url;
+ })
+ mods);
+ in
+ toFile "checksums-json" toWrite;
+in {
+ inherit mkChecksums;
+
+ # this is probably what you're looking for if
+ # you're an end user trying to implement a modpack in
+ # your module.
+ #
+ # `pkgs` is an instance of nixpkgs for your system,
+ # must at least contain `fetchurl`.
+ #
+ # `checksums` is a json file from an upstream modpack
+ # containing the names, urls, and sha256sums of mods
+ #
+ # attrset -> path -> attrset
+ mkPackwizPackages = pkgs: checksums: genMods pkgs (fromJSON (readFile checksums));
+
+ # this creates an `apps` attribute for a flake
+ # which runs a bash script to generate a checksums
+ # file
+ #
+ # `pkgs` is an instance of nixpkgs for your system,
+ # must at least contain `writeShellScriptBin`
+ #
+ # `dir` is a path to the folder containing your .pw.toml files
+ # files for mods. make sure they are the only files in the folder
+ #
+ # attrset -> path -> attrset
+ mkChecksumsApp = pkgs: dir: let
+ inherit (pkgs) writeShellScriptBin;
+ checksums = mkChecksums dir;
+ name = "generate-checksums";
+ script = writeShellScriptBin name ''
+ cat ${checksums} > checksums.json
+ '';
+ in {
+ type = "app";
+ program = script.outPath + "/bin/${name}";
+ };
+
+ # this creates an attrset value for
+ # minecraft-servers.servers.<server>.symlinks
+ # attrset -> attrset
+ mkModLinks = mods: let
+ fixup = map (name: {
+ name = "mods/" + fixupName name;
+ value = mods.${name};
+ }) (attrNames mods);
+ in
+ listToAttrs fixup;
+}