1. 34
    1. 11

      But please add .envrc to your .boring, .gitignore, .hgignore, .ignore or similar file & don’t commit .envrc to the repository. I see this mistake happen all the time & have projects trying to force their environmental settings on me instead of letting me decide echo "use flake" > .envrc && direnv allow is a simple enough one-liner if all you wanted was a Nix devShell, but once you need to modify these env vars, but direnv is meant for your personal setup & version control is going to start fighting with you the whole way if you need to make modifications.

      1. 3

        The pattern we have at work is to commit the .envrc if there’s shared setup/standard defaults needed, but also have source_env_if_exists .envrc.private in there, which is then the file all the personal tweaks, settings go into.

        I do still have envrc gitignored globally for easy use in projects that don’t use that pattern though. Just need to git add -f .envrc when wanting to commit it explicitly.

        1. 9

          I think you should make .envrc.example instead & cp .envrc.example .envrc if that is the case rather than the other way around of trying to build more things into a complex .envrc.

          1. 2

            I’d possibly go that route for public repos to be fair, internally at work direnv is how we expect our projects to be setup as a baseline and then writing our own .envrc.private for custom things (or Auth variables, see also env_vars_required) is the convention.

            I’d argue it’s not adding more things to the envrc, these functions are in the direnv stdlib after all and the private file is documented for exactly that use case. I get that it’s potentially surprising if you’ve not come across the pattern before though. And you always need to direnv allow when it’s changed in git so there’s no chance of changes happening without you being aware.

            1. 4

              While I definitely appreciate it asking for consent (unlike tools like Husky that installs scripts & modify your Git config without consent), it’s still such a jarring thing to cd into a repository I just met & it’s asking if I want to run scripts. The times I’ve run into this too were projects without extra config for .envrc.private since there wasn’t consideration for others, especially in the context of open source—which is why I find the example config a more user-friendly option to not even get red text “do you wanna run this thing you’ve net even had time to look at?” as a first impression.

              1. 1

                There’s nothing jarring about it. If you don’t like it, ask project responsible for it (direnv, nix-direnv, etc.) to let you disable it instead of expecting the whole world adjust to your preferences.

                1. 1

                  There’s nothing jarring about it. …

                  This reply is literally gaslighting.

                  If a website did an alert() when you first opened a page, it wouldn’t be Mozilla I would report it to. I wouldn’t suggest alert()s be removed. I would tell the maker of the site that they shouldn’t put alert()s on page load. This the reason why those PWA guidelines say to delay asking for geolocation until the user does something instead of on page load where a user doesn’t understand why a remote host is asking for it or if they should even trust it—with it being jarring enough some of APIs switched to requiring some user interaction prior to getting access to a sensor, filesystem, or other feature. Even if those pop-ups can deny consent in their dialog, privacy-minded folks will always deny & I-have-nothing-to-hide Harry will always accept, but it is more difficult & confusing to go back on that decision—and that is due to it being bad UX.

                  An .envrc should ask you to allow as it does & should by default because it speeds up the workflow of switching projects, but this shouldn’t happen when cding into a fresh project. User interaction first, like those web APIs, is cp .envrc.example or echo "use flake" > .envrc, and then you get the ANSI red pop-up message asking you to allow direnv to add. You should never be asked to execute code before you get a chance to read it & that is precisely what a default .envrc in a project root will do—since it is bad UX. Just like deciding to allow geolocation after it was denied earlier is unintuitive since the user agent knows you already denied it & would assume you don’t want to be asked again, when you deny direnv, remembering the command to allow it is more difficult since direnv knows you already denied it.

                  Thinking this is a bad user experience for developers isn’t some unfounded premise.

                  1. 1

                    This reply is literally gaslighting.

                    “literally” rolling eyes

                    User interaction first, like those web APIs, is cp .envrc.example or echo “use flake” > .envrc

                    I don’t want to be doing that, I’m happy that in a project with a nix shell (or whatever else automation like that), I get this notification immediately. Part of the reason why I installed nix-direnv. If I cd into a project I cloned locally I probably want to start hacking on it. And if I don’t I answer no.

                    It’s just your preference. Deal with it.

                    You literally installed the software that has this behavior on your system, and you could configure it not to display that prompt at all and live happily. Instead you think the whole world should adjust to you.

                    1. 1

                      I just re-read both manpages & the best you can do is have direnv automatically execute without the prompt.

                      This feature should be used with great care, as anyone with the ability to write files to that directory (including collaborators on VCS repositories) will be able to execute arbitrary code on your computer.

                      This warning shows it as unsafe. And I would never want that behavior. …Just like you shouldn’t arbitrarily direnv allow a new project without having a chance to read it first. If you didn’t get the parallel example about brower geolocation then I’m afraid you’re totally lost as to why this is an issue. Popularity contests aren‘t an amazing metric, but my comments in the thread have more upvotes (folks that agree) than the others which is saying something. Your preference of committing that file leads to a worse UX. Adding one cp/echo step before folks “hack on it” is not a burden and will default to allowing contributors the freedom to customize the .envrc without needing to send patches to allow add the flags for .envrc.private, etc. in the committed file.

      2. 1

        At my last place we used a shellHook in shell.nix which looked for the presence of various files, like .envrc, .editorconfig, etc. and copied defaults into place if they didn’t already exist. There were some smarts too, like checking if they appear in .gitignore, checking for the presence of comments like ### AUTO-GENERATED, etc. to decide whether it’s OK to overwrite an existing file. These shell hooks were modular, centrally defined, and used across many different repos (whose shell.nix was usually a one-liner)

    2. 5

      An example .envrc with some useful features:

      #!/usr/bin/env bash
      watch_file nix/* vcard/version.txt ./*.nix poetry.lock pyproject.toml
      use nix
      ln --force --no-target-directory --symbolic "$(which python)" python
      
      • The shebang line means shellcheck can verify the file - apparently .envrc files are just shell scripts.
      • By default nix-direnv only watches default.nix and shell.nix - any other files whose changes should result in a rebuild need to be listed explicitly.
      • The last line creates a symlink from the environment Python executable right at the root of the project. This creates a fixed path for the interpreter, which makes it easy to configure the project SDK in JetBrains IDEs. These IDEs don’t support just pulling the SDK from $PATH, so if you don’t do this you’ll have to change the SDK every time the Python executable ends up in a new Nix store path. (The symlink should be ignored from your repo.)
      1. 1

        Super useful, will use it, thanks! I really like the idea of keeping a link to the python exe in the root of the repo.

        Do you also have some tricks for regenerating python venvs if python changes?

        1. 2

          If one uses python.withPackages to build their environment, then that’ll be handled automatically by Nix. The python symlink would not link to a bare Python binary, but a shell script that wraps Python and sets up all of the library paths.

          1. 2

            Yep, on the command line you can do nix-shell --packages 'python3.withPackages(ps: [ps.numpy ps.pytest])' to get a Python interpreter with numpy and pytest “built in”. You can put (python3.withPackages(ps: [ps.numpy ps.pytest])) in your list of packages in your Nix shell to get the same effect.

            1. 1

              If I’m not mistaken, this will limit me to nixpkgs versions of python packages?

              My approach so far has been to keep pyproject.toml/requirements.txt around and regenerate .venv every time I update python. But that’s rather manual and not so robust.

              1. 2

                It’s possible to add arbitrary Python packages; all that is required is buildPythonPackage. For example, in this flake, I include Nix expressions for Python packages llama-cpp-python, sentence-transformers, and pymediawiki alongside expressions from nixpkgs.

    3. 3

      I switched to using devenv as a huge quality of life improvement. It uses nix-direnv under the hood, but allows to describe project dependencies in a more structured way than shell.nix.

      1. 2

        this look awesome!

        Not sure this entirely fit my current needs, but it would have helped me a lot if I knew about it earlier.

        For example, I built my own, postgres/redis/elasticsearch services in nix, and I use trap on quit to delete the local database. That way I can start my local dev with a clean DB every time I restart nix-shell.