Help Needed: Repackaging Proprietary launcher

Hey There! I am really enjoying my nixos experience so far! But right now I am stuck trying to repackage a software I regularly use with FHS environments. This is the script I worked out so far:

{ lib
, stdenv
, buildFHSUserEnvBubblewrap
, fetchurl
, dpkg
, pkgs
}:

let
  amsel-suite = stdenv.mkDerivation rec {
    pname = "amsel-suite";
    version = "1.4.2";

    src = fetchurl {
      url = "https://github.com/OllamTechnologies/launcher-releases/releases/download/v${version}/amsel-suite_${version}_amd64.deb";
      hash = "sha256:d723659cdca890ee5ca15325bf3fd8d0feb346367541e1ca154704699daddc26";
    };

    nativeBuildInputs = [ dpkg ];

    unpackCmd = "dpkg -x $curSrc $TMPDIR/src || true";

    installPhase = ''
      mkdir -p $out
      cp -r $TMPDIR/src/* $out
    '';

    meta = with lib; {
      description = "Launcher for the Amsel Suite by Ollam Technologies";
      homepage = "https://ollam.ai/";
      license = licenses.unfree; # falls unklar, unfree setzen
      platforms = [ "x86_64-linux" ];
      maintainers = with maintainers; [ yourGithubHandle ];
      sourceProvenance = with sourceTypes; [ binaryNativeCode ];
    };
  };

  amsel-suite-fhs = buildFHSUserEnvBubblewrap {
    name = "amsel-suite-fhs";

    targetPkgs = pkgs: with pkgs; [
      glib
      nss
      nspr
      dbus.lib
      at-spi2-atk
      cups.lib
      gtk3
      pango
      cairo
      xorg.libX11
      xorg.libXcomposite
      xorg.libXdamage
      xorg.libXfixes
      xorg.libXrandr
      libgbm
      xorg.libxcb
      libxkbcommon
      alsa-lib
      ffmpeg
      libdrm
      xorg.libXext
      expat
      amsel-suite
    ];

    # Wrapper, der persistente Ordner anlegt
    runScript = pkgs.writeShellScript "amsel-suite-wrapper" ''
      set -euo pipefail

      PERSIST_BASE="$HOME/.local/share/amsel-suite"

      # Unterordner wie bei Steam anlegen
      for dir in home opt usr-local; do
        mkdir -p "$PERSIST_BASE/$dir"
      done

      exec amsel-suite "$@"
    '';

    extraMounts = [
      {
        source = "${builtins.getEnv "HOME"}/.local/share/amsel-suite/home";
        target = "/home/amsel";
        writable = true;
      }
      {
        source = "${builtins.getEnv "HOME"}/.local/share/amsel-suite/opt";
        target = "/opt";
        writable = true;
      }
      {
        source = "${builtins.getEnv "HOME"}/.local/share/amsel-suite/usr-local";
        target = "/usr/local";
        writable = true;
      }
    ];
  };
in
amsel-suite // {
  passthru = { fhsEnv = amsel-suite-fhs; };
}

There are multiple issues with this script, but I cannot figure out how to get it working.

First off, when unpacking the deb, tar complains about being unable to set a sticky bit on chrome-sandbox. Then, when executing the binary in the nix-store it crashes with broken pipes.

The software itself is a launcher which downloads further apps to /opt and executes them. I am wondering what I need to change in order to get a running application in the nix-store. I am relatively new to repackaging binaries, so please feel free to point out if all I have done is crap and point me towards correct ways of implementing this!

Thank you very much in advance!

1 Like

Some of my references include:

https://nixos.wiki/wiki/Packaging/Binaries

So I’ve made some progress. Following is my current derivation:

{
  lib,
  stdenv,
  buildFHSEnvBubblewrap,
  fetchurl,
  dpkg,
  pkgs,
  makeWrapper,
  wrapGAppsHook,
  extraPkgs ? pkgs: [],
}:
stdenv.mkDerivation rec {
  pname = "amsel-suite";
  version = "1.4.2";

  src = fetchurl {
    url = "https://github.com/OllamTechnologies/launcher-releases/releases/download/v${version}/amsel-suite_${version}_amd64.deb";
    hash = "sha256:d723659cdca890ee5ca15325bf3fd8d0feb346367541e1ca154704699daddc26";
  };

  nativeBuildInputs = [dpkg wrapGAppsHook makeWrapper];

  unpackCmd = ''dpkg -x $curSrc src || true'';

  fhsEnv = buildFHSEnvBubblewrap {
    pname = "${pname}-fhs-env";
    inherit version;

    targetPkgs = pkgs: let
      sudoShim = pkgs.writeShellScriptBin "sudo" ''
        #!/bin/sh
        echo "[amsel-fhsenv] sudo shim: running without privileges"
        # Führt den Befehl ohne Rechte aus (nur innerhalb des FHS-Env)
        exec "$@"
      '';
    in
      with pkgs;
        [
          glib
          gsettings-desktop-schemas
          hicolor-icon-theme
          nss
          nspr
          dbus.lib
          at-spi2-atk
          cups.lib
          gtk3
          pango
          cairo
          xorg.libX11
          xorg.libXcomposite
          xorg.libXdamage
          xorg.libXfixes
          xorg.libXrandr
          libgbm
          xorg.libxcb
          libxkbcommon
          alsa-lib
          ffmpeg
          libdrm
          xorg.libXext
          libGL
          udev
          expat
        ]
        ++ extraPkgs pkgs;

    # Wrapper, der persistente Ordner anlegt
    # erzeuge die Host-Ordner (wird beim Start des wrappers ausgeführt)
    extraPreBwrapCmds = ''
      mkdir -p "$HOME/.local/share/amsel-suite/opt"
    '';

    # bwrap-Argumente: binden der Host-Pfade in das FHS-Environment
    # $HOME bleibt eine Laufzeit-Variable (wird vom erzeugten Startskript expandiert)
    extraBwrapArgs = [
      "--bind-try $HOME/.local/share/amsel-suite/opt /opt"
    ];
    runScript = "";
  };

  dontConfigure = true;
  dontBuild = true;

  installPhase = ''
    runHook preInstall

    mkdir -p $out
    mv usr/ $out
    makeWrapper ${fhsEnv}/bin/${pname}-fhs-env $out/usr/lib/amsel-suite/amsel-suite \
      --add-flags "$out/usr/lib/amsel-suite/Amsel\ Suite" \
      "''${gappsWrapperArgs[@]}"

    rm $out/usr/bin/amsel-suite
    ln -s $out/usr/lib/amsel-suite/amsel-suite $out/usr/bin/amsel-suite

    runHook postInstall
  '';

  meta = with lib; {
    description = "Launcher for the Amsel Suite by Ollam Technologies";
    homepage = "https://ollam.ai/";
    license = licenses.unfree; # falls unklar, unfree setzen
    platforms = ["x86_64-linux"];
    maintainers = with maintainers; [fstracke];
    sourceProvenance = with sourceTypes; [binaryNativeCode];
  };
}

However, when the program tries to install downloaded binaries after extraction, it fails returning an error to the user. Has anyone an Idea how I can enable the program to install further binaries especially under /opt?

You can’t make it install anything to /opt, but you could make it install to $out/opt, which could get symlinked by buildFHSEnv.

Out of curiosity, did you try building this app without all the FHS stuff? Is it just unfeasible to do?

yep, the fhs env is definitly necessary. Tested it only using derivations and it fails loading node modules delivered with the app.

Okay, so further progress:
I was able to figure out that the binary is using the npm package sudo-prompt (https://www.npmjs.com/package/sudo-prompt?activeTab=code), which internally is trying to run pkexec or kdesudo. I’ll try and create simple wrappers for these programs and see if it works.

That was it. Still has some errors but works mostly for now.