Create file with builtins.readFile & systemd.tmpfiles.rules

I’m trying to import a file for an install iso. Here is the part I can’t get working:

{ pkgs, ... }:

let
  disk-layout = builtins.readFile ./disk-layout.nix;
in
{
  systemd.tmpfiles.rules = [
    "f /home/nixos/disk-layout.nix 0777 nixos users - ${disk-layout}"
  ];
}

I end up with the file, but it only contains, I think, the first character of the file. What am I missing?

It ends up containing the verbatim text, as a string. This probably ends up looking like a single character in rules, because there probably is a newline somewhere or tmpfiles.rules doesn’t parse stuff beyond that character correctly. Most likely this results in all kinds of brokenness.

To import nix as code, use import instead.

That said, what you’re sharing here doesn’t make any sense to me in general. I think this is an XY problem; there is probably a much better solution to what you’re attempting. Mind explaining:

  1. What you want to ultimately achieve?
  2. What disk-layout.nix contains?
1 Like

I’d just drop the readFile and inline it - also likely you’ll want L or something similar like C instead of f so you don’t need nix to read the contents.

systemd.tmpfiles.rules = [
    "L /home/nixos/disk-layout.nix 0777 nixos users - ${./disk-layout.nix}"
  ];

But yeah this seems extremely strange and x-y.

1 Like

disk-layout.nix is a disko config file. I’m trying to make an offline install iso. Right now I can boot my iso then curl or git clone to get the file. Then I use that file to partition the disk as part of the nix install.

Why are you trying to place this file somewhere with systemd.tmpfiles.rules then?

Trying to make an offline installer, no internet. I’m just trying to get the file on the iso that gets built. So I can use it when I boot it up to do an install.

Thanks! The C option was the way to go.

This seems like the wrong approach to that; I think you’re better off including a template repo that you copy into the target /etc/nixos (or wherever you put your config). I’d include a step for that in my general installation tooling.

An approach I could imagine e.g. with nixos-anywhere (that doc includes a good guide for setting up such a template repo, I’m assuming you’re not involving flakes here) would be something like:

{ pkgs, lib, ... }: {
  environment.systemPackages = let
    nixEntryPoint = pkgs.writeText "default.nix" /* nix */ ''
      # default.nix
      import <nixpkgs/nixos/lib/eval-config.nix> {
        modules = [ ./configuration.nix ];
      }
    '';
    install-prep = pkgs.writers.writeNuBin "nixos-install-prepare" /* nu */ ''
      # Yeah, sorry, written in nu since I find this more pseudocodey
      let tmpdir = mktemp -d
      nixos-generate-config --no-filesystems --dir $tmpdir
      cp '${./disko-config.nix}' $tmpdir
      cp '${nixEntryPoint}' $'($tmpdir)/default.nix'
      $tmpdir
    '';

    # It's probably possible to pre-generate the store path for `diskoScript`,
    # but I'm too lazy to find out how to evaluate disko standalone right now,
    # and you need to evaluate the other store path anyway since you'll
    # be editing `hardware-configuration.nix` and `configuration.nix` at install
    # time.
    #
    # This also gives you the flexibility of editing your disko config ad-hoc,
    # should you need to.
    nixos-anywhere = pkgs.runCommand "nixos-anywhere" /* bash */ ''
      makeWrapper '${lib.getExe pkgs.nixos-anywhere}' $out/bin/nixos-anywhere \
        --prepend-flags '--store-paths $(nix-build -A config.system.build.diskoScript -A config.system.build.toplevel --no-out-link)'
    '';
  in [
    install-prep
    nixos-anywhere
  ];
}

Then, at installation time, you just run cd $(nixos-install-prepare), edit the resulting configuration.nix according to your preferences, and then call nixos-anywhere root@localhost; no need for systemd.tmpfiles shenanigans.

This also lets you use all the excellent other nixos-anywhere flags, such as --extra-files and whatnot, which you will undoubtedly find useful at some point for an installer. Let’s you e.g. add the config generated with install-prep to the target’s /etc/nixos, or generate SSH keys during the installation process.

1 Like

Thanks! I’ll give it a shot.

Note it’s pseudo-codey and untested :wink: