{
  lib,
  runCommand,
  pkgs,

  name,
  packages,
  services ? [],
  osId ? "patos",
  version ? null,
}:


let
  metadata = {
    ID = osId;
    VERSION_ID = osId;
    IMAGE_ID = name;
    IMAGE_VERSION = version;
  } // lib.optionalAttrs (services != []) { EXTENSION_RELOAD_MANAGER = "1"; };

  metadataFile = lib.concatStringsSep "\n" (
    lib.mapAttrsToList (k: v: "${k}=${v}") (lib.filterAttrs (_: v: v != null) metadata)
  );

  doCopy =
    {
      drv,
      prefix ? "usr",
      path,
      destpath ? null,
    }:
    "do_copy ${prefix} ${drv} ${path} ${drv.name} " + builtins.concatStringsSep "," (map (l: l.shortName or "unknown") (lib.toList (drv.meta.license or []))) + lib.optionalString (destpath != null) " ${destpath}";

in

runCommand name
  {
    passthru.name = name;
    inherit metadataFile;
    passAsFile = [ "metadataFile" ];

    nativeBuildInputs = [
      pkgs.erofs-utils
      pkgs.cryptsetup
      pkgs.gawk
      pkgs.jq
    ];

  }
  ''
    set -ex -o pipefail
    do_copy () {
      local prefix="$1"
      local drv="$2"
      local path="$3"
      local pkgname="$4"
      local license="$5"
      local destpath="''${6:-$path}"

      local srcfile
      local destdir
      local destfile
      srcfile="$drv/$path"
      destfile="$out/tree/$prefix/$destpath"
      destdir="$(dirname -- "$destfile")"

      echo "pkgname=\"$pkgname\",licenses=\""$license"\"" >> $out/.tmp-pkgs.txt

      mkdir -pv "$destdir"

      # recursively copy if ending with /
      if [[ "$destfile" =~ /$ ]]; then
        basedir="$(dirname -- "$destfile")"
        chmod -R 755 "$basedir"
        # remove if exists
        for f in $srcfile/*; do
          basename="$(basename -- "$f")"
          rm -rf "$destfile/$basename"
        done
        cp -rPv "$srcfile" "$basedir"
        chmod -R 755 "$basedir"
        for f in $destfile/*; do
          interpreter=$(patchelf --print-interpreter $f || echo "")
          [ -n "$interpreter" ] && ldLinux=$(basename $interpreter)
          patchelf --set-interpreter /lib/$ldLinux $f || true
          patchelf --set-rpath /usr/lib $f || true
        done
        return
      fi

      cp -Pv "$srcfile" "$destfile"

      chmod 755 "$destfile"
      interpreter=$(patchelf --print-interpreter $destfile || echo "")
      [ -n "$interpreter" ] && ldLinux=$(basename $interpreter)
      patchelf --set-rpath /usr/lib $destfile || true
      patchelf --set-interpreter /lib/$ldLinux $destfile || true
    }

    do_service () {
      local unit="$1"
      local content="$2"

      local unit_file="$out/tree/usr/lib/systemd/system/$unit"

      mkdir -p $out/tree/usr/lib/systemd/system
      echo "$content" > $unit_file

      # look for [Install] section and WantedBy in unit
      if ! grep -q "^\[Install\]" "$unit_file"; then
        echo "No [Install] section found in $unit_file"
        return
      fi

      local wanted_by=$(sed -n '/^\[Install\]/,/^\[/{/^WantedBy=/s/^WantedBy=//p}' "$unit_file")

      if [ -z "$wanted_by" ]; then
        echo "No WantedBy found in [Install] section of $unit_file"
        exit 1
      fi

      mkdir -p $out/tree/usr/lib/systemd/system/"$wanted_by".wants
      ln -s ../$unit $out/tree/usr/lib/systemd/system/"$wanted_by".wants/$unit
    }

    mkdir -p $out/tree

    ${lib.concatStringsSep "\n" (map doCopy packages)}
    ${lib.concatStringsSep "\n" (map (service: "do_service '${service.unit}' '${service.content}'") services)}

    # bake metadata into the structure
    if ! [ -f $out/tree/usr/lib/extension-release.d/extension-release."${name}" ]; then
      mkdir -p $out/tree/usr/lib/extension-release.d
      cat "$metadataFilePath" > $out/tree/usr/lib/extension-release.d/extension-release."${name}"
    fi

    pushd $out
    find tree -type d -exec chmod 0755 {} \;
    mkfs.erofs -zlz4hc,12 -C1048576 -Efragments,dedupe,ztailpacking --all-root $name.raw tree/
    veritysetup format --root-hash-file $name.roothash $name.raw $name.verity
    # TODO: pcks7 signature
    # openssl smime -sign -nocerts -noattr -binary -in ${name}.roothash \
    #   -inkey key.pem -signer cert.pem -outform der -out ${name}.roothash.p7s

    # create contents list
    pushd tree
    find . -ls > $out/"$name"_contents.txt
    popd

    # create nixpkgs packages list
    sort -u $out/.tmp-pkgs.txt > $out/"$name"_packages.txt
    rm -f $out/.tmp-pkgs.txt
    jq -R -s 'split("\n") | map(select(length > 0)) | map(capture("pkgname=\"(?<name>[^\"]*)\",licenses=\"(?<licenses>[^\"]*)\"") | .licenses |= split(",")) | map(select(. != null))' $out/"$name"_packages.txt > $out/"$name"_packages.json


    rm -rf tree
    sha256sum * > SHA256SUMS
    ln -s SHA256SUMS SHA256SUMS.asc
    # TODO: add gpg signature
    popd
  ''