Defining HOME in flake

Hey! it’s been a while that I am using Nix, however, I consider myself a newbie. It was refreshing that I found a community who cares about reproducibility in our industry, as I think our industry exists because of digital computation that made it more reproducible than the analog computations before. So I am happy to be among you :slight_smile:

That being said, I only started to using flake yesterday and I blocked! I think in addition to reproducibility, isolation is a good target to have, which opens the doors for scalability, therefore, in my shell.nix files I always defined the HOME variable to be inside my working directory to isolate most of the side effects of my work with the current project inside the project’s directory. Thus, I can refresh everything in the project by just removing that directory, which feels good! I know it would duplicate the configs and caches, and also, sometimes it’s not very easy to achieve complete isolation with current tools, but isolation is what I sought.

My current blocker is that in shell.nix

        userHome = "${builtins.toString ./.user-home}";

it will be a path inside my currently working directory, but in flake.nix it’s a source directory in nix store, which is also complaining that the filesystem is read only. By the way, I tried the --impure option but there’s no difference! I consider it as a breaking API. But when I searched around I cannot convince myself that it’s a good change. For instance, I found

Obviously you cannot purely depend on the flake’s location on your filesystem, which may change across evaluations or not exist at all

in Possible to impurely read $HOME in flakes by using `~`-paths · Issue #6684 · NixOS/nix · GitHub, while it’s not obvious for me, but I understand it. The problem is that not everything in the world is pure, and the opposite of pure is not impure, it’s side effects, which looks like Nix should provide more tools around them. Maybe because some people think the learning curve is already too steep. But in the end, we need to accept the existence of side effects, then provide a solution for it. Maybe we need to simplify it a lot to keep the community around :smiley: But in the end, please make it easy for isolation of side effects, such as defining the HOME directory.

I may be wrong about all of this, so please let me know if you have a solution. Thanks!

Additionally, flakes have too many indention! If I couldn’t find a solution, I am going to switch back to shell.nix for now :smiley: Thanks for your time.

Thanks for posting. I’m glad you have been enjoying your time with nix so far.

I think the answer to your question isn’t very easy with flakes but also depends on what you are using $HOME for… can you share some context please? We might end up in a situation where you need to conceptually rework some parts of your flake… let’s see.

Sure :slight_smile: Right now I am working with an Android project, so I need all the Gradle caches, where goes into ~/.gradle, and all android stuff, where goes into ~/.android, to be separated for this project. But it’s not only this kind of project. When I work on a Rust project, I expect all the cargo stuff stay isolated in the project directory. When I do node, or pipe, I expect the same, etc.

Eventually the goal is to isolate as much as possible. Maybe in the same level as docker. The problem with docker is that I cannot launch Android Studio inside the docker, or another problem is that it doesn’t have kernel support in MacOS, so it’s a VM, thus it’s slow, etc. Also docker is not as good as Nix in caching because it doesn’t respect purity.

Hope it helps.

I’m not sure I follow exactly. Maybe you can share a snippet or two of what you’re doing with this:

userHome = "${builtins.toString ./.user-home}";

Please let me know what you can so I can better understand your situation.


I expect all the cargo stuff stay isolated in the project directory

Sure, but that sounds more like a solution for something like direnv… and unrelated to nix :thinking:

➜  ~ mkdir foo; cd foo
➜  foo echo 'export CARGO_HOME=$(pwd)/.cargo' > .envrc
direnv: error /home/aaron/foo/.envrc is blocked. Run `direnv allow` to approve its content
➜  foo direnv allow .
direnv: loading ~/foo/.envrc
direnv: export +CARGO_HOME
➜  foo echo $CARGO_HOME
/home/aaron/foo/.cargo

Sure :slight_smile: Thanks for the time.

I am doing it like this

  userHome = "${builtins.toString ./.user-home}";
  androidUserHome = "${userHome}/.android";
  androidAvdHome = "${androidUserHome}/avd";


  androidEmulator = pkgs.androidenv.emulateApp {
    name = "emulate-android-nix";
    platformVersion = "31";
    abiVersion = "x86_64";
    systemImageType = "google_apis_playstore";
    androidUserHome = androidUserHome;
    androidAvdHome = androidAvdHome;
  };

where androidAvdHome keeps all the emulator files in the project directory, as I want to keep them in isolation.

Regarding the direnv solution and the above example, I don’t have access to CARGO_HOME on the let clause in the output of the flake.nix where I want to set my variables based on it. I can think of some workarounds, but I don’t like them, because this method has a big problem that even if I get access to CARGO_HOME value in the let clause, it defeats the single source of truth principle that I want to apply with the nix file in the first place. So I should be able to define the bash variables based on the ones in the nix file, not vice versa!

I haven’t used androidenv and after looking at the relevant code I’m sure I don’t understand… this code tells me that you can’t do what you want to do regardless because the path you are passing in androidUserHome is only used inside mkDerivation which is in a sandbox. You’ll have to explain to me what I’m missing for this example, but from what I see what you’re trying to do doesn’t even work pre-flakes :thinking:

For a dev environment I’m not sure why you even need CARGO_HOME inside nix at all. You said you want per project .cargo folders and direnv can do exactly that. Again, I will need more details…


I apologize that I seem to be asking more questions than providing answers… :sweat_smile: Anyone else feel free to step in if they understand the problem better than I do.

No worries :smiley: maybe I didn’t explain it well. let’s try again.

Yes, the mkDerivation is in a sandbox, but ANDROID_USER_HOME, which is defined based on androidUserHome can point to outside of the sandbox. Therefore, avdmanager can create the needed side effect data, which are the Anddroid virtual machines’ data, in that directory.

The

userHome = "${builtins.toString ./.user-home}";

totally works in the shell.nix because the current directory is the directory that shell.nix resides there, but this behavior is changed in flake.nix and it points to the source directory in the nix store, which is read only, of course.

Regarding,

I’m not sure why you even need CARGO_HOME inside nix at all.

defining environment variables is one of the reasons I use nix because I am thinking of the nix config file as the Single source of truth for dependencies and configurations as I mentioned before. Thus, I expect to be able to define CARGO_HOME inside my nix file. Additionally, I don’t want to delegate the responsibility of defining environment variables to the .envrc file, and I think it’s a valid request.

In the end, I appreciate your efforts. Maybe the problem is that I want to put everything in the right place, where clearly there are some workarounds out there. By the way, I am using workarounds all the time if I had to, but I assumed in the Nix community we care about correctness more than other communities.

Ah your explanation this time is working well for me now :slight_smile:

Unfortunately I think that the workflow you are using in nix isn’t congruent with flakes. I’ll quote myself at this point…

Then again… flakes isn’t mandatory, so you can happily continue along using nix-shell and pair it with something like niv if you are missing version locking from flakes.

Maybe someone has a better idea, but without becoming a bit more deeply aware of your stack unfortunately I don’t have too much else to offer at this point.

Sorry.

1 Like

I’m not sure to see, are you willing to isolate in a nix build or while using nix develop? If it’s the later, can’t you rely on a shell hook?

Hey! Thanks for the suggestion. I already tried the shellHook. I can use commands like pwd to get the project’s directory, but the problem is that I cannot pass any variable from that bash script to the nix side. Even though it is a great language design IMHO, it blocked me to retrieve the project’s directory in the nix side.