Trying to package my first software for NixOS

I’m a new NixOS user, currently trying to get all the software up an running on a NixOS system (currently inside a VM, but hopefully on my laptop soon).
I was amazed to find packages for almost any software I wished for - great work!

Now there is one application for which no package exists and I am trying to find a configuration that installs it to my NixOS: JAlbum.
I’d appreciate if someone could help me find my way around the NixOS configuration to package this.

What I know about this software:

  • name: jalbum
  • version: 37.7
  • There is a ZIP download to execute it with any Java interpreter: https://download.jalbum.net/download/37.7/jAlbum.zip
    • sha256: QGy8agZ88Q0npcodnP6S/BF4lQEGbUMlQa8v7T2kNWU=
    • contains a folder jAlbum with many things, including
      • JAlbum.jar
      • icons/JalbumApp48.png
  • On my Linux Mint system Java is started with these arguments to run it:
    • -Xmx8000m --add-exports=java.desktop/sun.awt.shell=ALL-UNNAMED -XX:+UseParallelGC -DmaxSubsampling=2 -DuseDesktop=true -jar /usr/lib/jalbum/JAlbum.jar
  • On NixOS I can start the application using java -jar /path/to/JAlbum.jar with this in my configuration:
programs.java = {
      enable = true;
      package = pkgs.jdk23.override { enableJavaFX = true; };
    };

What I think the package should do:

  • Include pkgs.jdk23 with JavaFX enabled or depend on it.
  • download the ZIP + check sha256
  • extract it to an appropriate location
  • create a starter script that calls Java with all the arguments
  • Create a .desktop launcher to make it show up in the menu (I am using KDE Plasma, in case that matters)

I don’t really know how to start – found some hints on the internet so I have a very vague understanding, but I’m not able to get it to work by myself.
Is the information above everything we need to create a custom package in my configuration?
How to proceed?

Some starting info:

Specifically in this case, you’re going to need to poke around the provided zip a bit, and see if they provide a starter script or something. If so, you’ll probably want to wrap it with makeWrapper, and possibly modify it a bit first with substituteInPlace. If not, you’ll just want to make one (actually, you may want to make it with makeWrapper anyway, just wrap the java binary and add additional arguments).

They probably also don’t provide a FHS-style directory structure (bin, share, lib, etc), so you’ll need to at least minimally conform to that, maybe by throwing everything in $out/share/jalbum or the like.

1 Like

Here’s an example of a derivation for a java-based game in nixpkgs:

In this case, the game provides a shell script intended for starting it, and the derivation modifies and wraps that.

1 Like

Great – thanks for pointing me into the right direction!

Looks like I’ll have to do some reading… :slight_smile:

1 Like

This looked complicated… but after reading the HowTo and looking at the derivation source you linked to, it wasn’t that bad at all :slight_smile:

Now I have JAlbum running on NixOS and I think all I need to change for future versions is the version and sha256 lines in the derivation.

Thank you very much, @tejing, you have been really helpful!


In case someone finds this thread and wants to do the same, here is my jalbum.nix:

{
  lib,
  fetchzip,
  makeWrapper,
  openjdk23,
  stdenv,
  copyDesktopItems,
  makeDesktopItem,
}:
let
  openjdk = openjdk23.override { enableJavaFX = true; };
in
stdenv.mkDerivation rec {
    pname = "jalbum";
    version = "37.7";

    src = fetchzip {
        url = "https://download.jalbum.net/download/${version}/jAlbum.zip";
        sha256 = "QGy8agZ88Q0npcodnP6S/BF4lQEGbUMlQa8v7T2kNWU=";
    };

    nativeBuildInputs = [
        copyDesktopItems
        makeWrapper
    ];

    dontBuild = true;

    desktopItems = [
        (makeDesktopItem {
            name = "jalbum";
            exec = "jalbum";
            icon = "jalbum";
            comment = meta.description;
            genericName = "jalbum";
            desktopName = "JAlbum";
            categories = [ "Graphics" ];
        })
    ];

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin $out/share/jalbum
    cp -r ./* $out/share/jalbum

    mkdir -p $out/share/icons/hicolor/48x48/apps
    ln -s $out/share/jalbum/icons/JalbumApp48.png \
      $out/share/icons/hicolor/48x48/apps/jalbum.png

    makeWrapper ${openjdk}/bin/java $out/bin/jalbum \
    --add-flags "-Xmx8000m --add-exports=java.desktop/sun.awt.shell=ALL-UNNAMED -XX:+UseParallelGC -DmaxSubsampling=2 -DuseDesktop=true -jar $out/share/jalbum/JAlbum.jar"

    runHook postInstall
    '';

  meta = with lib; {
    description = "Free Photo Gallery Software for Any Website";
    homepage = "https://jalbum.net";
    sourceProvenance = with sourceTypes; [ binaryBytecode ];
    license = licenses.unfree;
  };
}

Recommendations for improvements are of course welcome!

2 Likes

Great job. For a first derivation, this is particularly impressive. I haven’t tried to build and run it, but just by reading it, I suspect this is pretty much nixpkgs-ready code.

One (very) minor note: dontBuild = true; is almost certainly not necessary. The default buildPhase will just do nothing if it can’t find a Makefile. You might want to specify it anyway for clarity, though. Up to you.

1 Like

You’re right - deleting this line works fine, too. :+1:

Looks good enough for a first contribution. You can create a folder jalbum within nixpkgs/pkgs/by-name/ja at master · NixOS/nixpkgs · GitHub and drop your jalbum.nix into this folder as package.nix.

If you add

    passthru.updateScript = lib.getExe (writeShellApplication {
      name = "update-jalbum";
      runtimeInputs = [
        curl
        common-updater-scripts
        gnused
      ];
      text = ''
        LATEST_VERSION=$(curl -Lsf https://jalbum.net/en/downloadmirror | sed -n 's!^.*<h1>Download jAlbum \(.*\)</h1>!\1!p')
        update-source-version jalbum "$LATEST_VERSION"
      '';
    });

you can also automate updating version number and hash.

1 Like

A minor nitpick:

  meta = with lib; {
    description = "Free Photo Gallery Software for Any Website";
    homepage = "https://jalbum.net";
    sourceProvenance = with sourceTypes; [ binaryBytecode ];
    license = licenses.unfree;
  };

can be rewritten to

  meta = {
    description = "Free Photo Gallery Software for Any Website";
    homepage = "https://jalbum.net";
    sourceProvenance = with lib.sourceTypes; [ binaryBytecode ];
    license = lib.licenses.unfree;
  };

That looks neat!

At which point will this be called?
Will NixOs use this every time I call sudo nixos-rebuild switch --upgrade or is this rather something that happens on the repo server side?

I’m unsure about contributing this to nixpkgs, since I currently cannot promise to keep this updated (I don’t even know if I’ll still be using Nix in a month).
Are one-time-contributions something that’s appreciated or is this frowned upon?

If we want to get rid of the with, why not go the full way and write

  meta = {
    description = "Free Photo Gallery Software for Any Website";
    homepage = "https://jalbum.net";
    sourceProvenance = [ lib.sourceTypes.binaryBytecode ];
    license = lib.licenses.unfree;
  };

?

To my eyes, that’s the cleanest-looking of the three versions.

The update script will be used by server-side automation or can triggered manually on a checkout of the nixpkgs repo, see GitHub - nix-community/nixpkgs-update: Updating nixpkgs packages since 2018.
One-time contributions are perfectly fine.

Packages generally need a maintainer, i.e. someone who promises to use the software and help maintain it. Unmaintained software will generally not be accepted.

But if you do stop using the software, or nix, you can send another PR removing yourself as maintainer - just be aware that the software may be removed from nixpkgs if no one steps up to maintain it and it becomes a maintenance burden.

Yes, this version is fine.