diff options
| -rw-r--r-- | .gitignore | 5 | ||||
| -rw-r--r-- | LICENSE | 21 | ||||
| -rw-r--r-- | README.md | 99 | ||||
| -rw-r--r-- | flake.nix | 5 | ||||
| -rw-r--r-- | lib/default.nix | 123 |
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 @@ -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; +} |
