How to copy files from directories in a derivation so that they can overwrite each other?

I am trying to package the Catppuccin theme for Steam. The instructions for installing the theme involve copying files from multiple sources into the same directory in a certain order so that files with the same name get overwritten.

Edit: Also I should mention there are enough individual files in the theme to worry about to make manually copying over each one I need infeasible.

However, I cannot figure out how to do this in a package.
I tried symlinkJoin, but it did not work because one of the source directories to copy from has spaces in its name.

Whenever I try to copy it as part of installPhase, I just get a bunch of errors like:

cp: cannot remove '/nix/store/yr3ci2m0f89920dd84ps004p61rkharw-catppucin-steam-theme/catppuccin-mocha/steam/cached/uninstallgamesdialog.res': Permission denied

Here is what I have so far:

{ stdenvNoCC
, fetchFromGitHub
, ...
}:

stdenvNoCC.mkDerivation {
  name = "catppucin-steam-theme";

  src = fetchFromGitHub {
    owner = "catppuccin";
    repo = "steam";
    rev = "7ea14ee1c40dcdba4cb6780c96a74c46e980e3ea";
    hash = "sha256-XFoYxzYncQqgs+oDn80S1ZEJCv61+wtZ0968Ga8lajg=";
  };

  metro = fetchFromGitHub {
    owner = "minischetti";
    repo = "metro-for-steam";
    rev = "v4.4";
    hash = "sha256-E/hmOODf/aBAcc/RYueqMjQ+7SuvftfjYCVKD6CTX+U=";
  };

  metroPatch = fetchFromGitHub {
    owner = "redsigma";
    repo = "UPMetroSkin";
    rev = "9.1.47";
    hash = "sha256-Fdvvpt+5z/wADcn9Iop/+puJ6VoEBbT7xL7K2eHq5ag=";
  };

  installPhase =
    let
      flavour = "mocha";
      themeFolder = "$out/catppuccin-${flavour}";
    in
    ''
      runHook preInstall

      mkdir -p ${themeFolder}
      cp -r $metro/* ${themeFolder}        
      cp -rf "$metroPatch/Unofficial 4.x Patch/Main Files [Install First]"/* ${themeFolder}
      cp -rf $src/themes/${flavour}/* ${themeFolder}

      runHook postInstall
    '';
}

Never mind, the theme was broken by Steam’s UI update a while ago so I can’t use it anyways.

Of course, I would still accept an answer to my post’s question if anyone has one because I’m sure it’ll be useful information to someone at some point.

Files and directories in the Nix store are read-only, and your copies are inheriting those mode bits, preventing you from writing to them.

The obvious ways I can think of to leave yourself with write bits are chmod -R +w between each layer, or cp --no-preserve=mode when copying.

2 Likes