Help with error: only HFS file systems are supported on Ventura

Hey all, I’ve been trying to update some derivations I have for macOS apps to point to more recent versions of those available in the wild.

I’m hitting a strange error:

building '/nix/store/1b4an9if0sdqgynwjbgybn93lnnb0kpz-hm_.authinfo.drv'...
building '/nix/store/bxx0a22lj1022fkxc17gslr1ls2a3lb0-authy-2.2.3.drv'...
unpacking sources
unpacking source archive /nix/store/18azal3rfigpw2c4warn04qixm4dfm0i-authy-x86_64-2.2.3.dmg
error: only HFS file systems are supported.
do not know how to unpack source archive /nix/store/18azal3rfigpw2c4warn04qixm4dfm0i-authy-x86_64-2.2.3.dmg
error: builder for '/nix/store/bxx0a22lj1022fkxc17gslr1ls2a3lb0-authy-2.2.3.drv' failed with exit code 1;
       last 4 log lines:
       > unpacking sources
       > unpacking source archive /nix/store/18azal3rfigpw2c4warn04qixm4dfm0i-authy-x86_64-2.2.3.dmg
       > error: only HFS file systems are supported.
       > do not know how to unpack source archive /nix/store/18azal3rfigpw2c4warn04qixm4dfm0i-authy-x86_64-2.2.3.dmg
       For full logs, run 'nix log /nix/store/bxx0a22lj1022fkxc17gslr1ls2a3lb0-authy-2.2.3.drv'.
error: 1 dependencies of derivation '/nix/store/qbb0zg93a694nw8c6gznhdzp414v6z03-home-manager-applications.drv' failed to build

My app.nix function is as follows:

{
  # custom args
  name,
  appname ? name,
  version,
  src,
  description,
  homepage,
  postInstall ? "",
  sourceRoot ? ".",
  # nix supplied
  pkgs,
  stdenv,
  lib,
  undmg,
  unzip,
  ...
}:

if stdenv.isDarwin then
  [(stdenv.mkDerivation {
    name = "${name}-${version}";
    version = "${version}";
    src = src;
    buildInputs = [ undmg unzip ];
    sourceRoot = sourceRoot;
    phases = [ "unpackPhase" "installPhase" ];
    installPhase = ''
      mkdir -p "$out/Applications/${appname}.app"
      cp -pR * "$out/Applications/${appname}.app"
    '' + postInstall;
    meta = {
      description = description;
      homepage = homepage;
      maintainers = [ "ldeck <ldeck@example.com>" ];
      platforms = lib.platforms.darwin;
    };
  })]
else
  []

The app in question (Authy) is defined as a module as follows:

{ config, lib, pkgs, ... }:
with lib;

let
  cfg = config.macOS.apps.authy;
  stdenv = pkgs.stdenv;
  arch = if stdenv.isDarwin then stdenv.hostPlatform.darwinArch else stdenv.system;
  toHyphenedLower = str:
    (lib.strings.toLower (builtins.replaceStrings [" "] ["-"] str));

  archSpecs = {
    x86_64-darwin = rec {
      version = "2.2.3";
      revision = "";
      date = "";
      arch = "amd64";
      url = "https://pkg.authy.com/authy/stable/${version}/darwin/x64/Authy%20Desktop-${version}.dmg";
      sha256 = "a75657222028822949516805f5af5406d4a786d0db0a9f91bd04cc08779883df";
    };
    aarch64-darwin = rec {
      version = "2.2.3";
      revision = "";
      date = "";
      arch = "arm64";
      url = "https://pkg.authy.com/authy/stable/${version}/darwin/x64/Authy%20Desktop-${version}.dmg";
      sha256 = "a75657222028822949516805f5af5406d4a786d0db0a9f91bd04cc08779883df";
    };
  };

in {
  options = {
    macOS.apps.authy = {
      enable = mkOption {
        default = false;
        description = "Whether to enable this app.";
      };
      sourceRoot = mkOption {
        default = "Authy Desktop.app";
        description = "The app folder name to recursively copy from the install archive. e.g., Foo.app";
      };
      version = mkOption {
        default = archSpecs.${stdenv.hostPlatform.system}.version;
        description = "The version of the app.";
      };
      date = mkOption {
        default = archSpecs.${stdenv.hostPlatform.system}.date;
        description = "The build date (if applicable).";
      };
      revision = mkOption {
        default = archSpecs.${stdenv.hostPlatform.system}.revision;
        description = "The build number of the app (if applicable).";
      };
      url = mkOption {
        default = archSpecs.${stdenv.hostPlatform.system}.url;
        description = "The url or url template for the archive.";
      };
      sha256 = mkOption {
        default = archSpecs.${stdenv.hostPlatform.system}.sha256;
        description = "The sha256 for the app.";
      };
    };
  };
  config = mkIf cfg.enable {
    home.packages =
      (pkgs.callPackage ./lib/app.nix rec {
        name = "authy";
        description = "Two-factor authentication software";
        sourceRoot = cfg.sourceRoot;
        version = cfg.version;
        src = pkgs.fetchurl {
          url = cfg.url;
          sha256 = cfg.sha256;
          name = "${(toHyphenedLower name)}-${arch}-${version}.dmg";
        };
        appcast = "https://formulae.brew.sh/api/cask/authy.json";
        homepage = "https://authy.com/";
      });
  };
}

I assume it’s something to do with undmg. But any suggestions on why this might be failing?
I can download the same dmg manually and happily open it.

nix-shell -p nix-info --run "nix-info -m"
 - system: `"x86_64-darwin"`
 - host os: `Darwin 22.3.0, macOS 10.16`
 - multi-user?: `yes`
 - sandbox: `no`
 - version: `nix-env (Nix) 2.8.1`
 - channels(root): `"nixpkgs"`
 - nixpkgs: `/nix/var/nix/profiles/per-user/root/channels/nixpkgs`

I’ve run into this too. The problem is that DMGs can be HFS or APFS, but undmg only supports extracting the former (HFS). What’s likely happened is upstream is now creating APFS DMGs, which is causing the build failure when you try to bump the version.

Thanks @reckenrode. Oh that’s a shame!

Is there an issue tracking this you’re aware of? I imagine there’ll be more and more APFS DMGs appearing for Apple Silicon support etc.

https://github.com/matthewbauer/undmg/issues/4

1 Like

@matthewbauer do you have any suggestions for this?

@reckenrode – I’ve not been able to get any responses from @matthewbauer, unfortunately, which makes me a little worried about continuing to depend on undmg.

I’m wondering if there might be an alternative to undmg for macOS? Presumably undmg exists primarily for darwin and to be a pure implementation within Nixpkgs. But for my purposes I don’t plan on needing this for linux.

homebrew makes use of dmg images all the time, presumably without the need for a custom tool, relying on the macOS facilities.

So I’m wondering if there’s a way to implement an “undmg” that essentially makes use of os tools to do its job?

Homebrew avoids the issue by using hdiutil to mount the image. That might be a place to start.

Thanks @reckenrode . What they’re doing is seemingly overly complex, or at least for my needs thus far.

The following unpackCmd is much simpler and does the job for me :slight_smile:

unpackCmd = ''
      echo "File to unpack: $curSrc"
      if ! [[ "$curSrc" =~ \.dmg$ ]]; then return 1; fi
      mnt=$(mktemp -d -t ci-XXXXXXXXXX)

      function finish {
        echo "Detaching $mnt"
        /usr/bin/hdiutil detach $mnt -force
        rm -rf $mnt
      }
      trap finish EXIT

      echo "Attaching $mnt"
      /usr/bin/hdiutil attach -nobrowse -readonly $src -mountpoint $mnt

      echo "What's in the mount dir"?
      ls -la $mnt/

      echo "Copying contents"
      shopt -s extglob
      DEST="$PWD"
      (cd "$mnt"; cp -a !(Applications) "$DEST/")
    '';

Full function here.

2 Likes

There’s an even simpler solution:

  nativeBuildInputs = [ _7zz ];

  # The following is no longer needed, thanks to #289900.
  #
  # unpackCmd = ''
  #   7zz x $curSrc
  # '';

Whoa, what evil trickery does 7zz have up its sleeve? This is great! I’ll rework #289900 to use 7zz. Seems there is no need for undmg at all then… Would you agree @wegank ?

For anyone interested it is now possible to use _7zz as a nativeBuildInput and its setup hook will unpack DMGs (HFS and APFS based) :tada:

1 Like