direnv icon indicating copy to clipboard operation
direnv copied to clipboard

Running a command within a direnv as if not

Open jwiegley opened this issue 7 years ago • 4 comments

I've found that nix-build doesn't like to run in a direnv-controlled environment, prompting me to often use this pattern:

cd ..
(cd proj ; nix-build)

in order to run the nix-build in a clean environment.

What I wonder is: Is there a command that will let me do this without needing cd and the directory change hook to take place? I'd like to apply it within scripts as well, where this trick does not work.

jwiegley avatar Jan 25 '19 01:01 jwiegley

hey John. I'm using Nix and didn't witness this issue (yet). Do you mind sharing a bit more information on the failure that you are seeing?

If the issue is that direnv is not reloading properly, you can use watch_file <filename> from the direnv stdlib for direnv to reload automatically (on next prompt) on other file changes than the .envrc.

If the issue is that nix-build is breaking then I will need more information as I don't know what that could come from.

zimbatm avatar Jan 25 '19 23:01 zimbatm

For example, if I cd into my category-theory project, I get:

Vulcan ~/src/category-theory $ nix-build
these derivations will be built:
  /nix/store/9nvgfyirg3lhfnzrlljkp27rd5lb9b6p-category-theory.drv
building '/nix/store/9nvgfyirg3lhfnzrlljkp27rd5lb9b6p-category-theory.drv'...
unpacking sources
variable $src or $srcs should point to the source
builder for '/nix/store/9nvgfyirg3lhfnzrlljkp27rd5lb9b6p-category-theory.drv' failed with exit code 1
error: build of '/nix/store/9nvgfyirg3lhfnzrlljkp27rd5lb9b6p-category-theory.drv' failed

But if I nix-build without letting direnv setup the environment, it works fine. I'm not sure which environment variable is causing this problem, though.

jwiegley avatar Jan 25 '19 23:01 jwiegley

Is this something I can reproduce locally? I would need to take a look at the nix code to understand why src is missing. Can you also paste the list of environment variables that direnv is changing?

zimbatm avatar Jan 26 '19 20:01 zimbatm

@zimbatm This issue has stalled, but the original question was never answered: Is there a way to execute a single command as if in the context of a directory?

My case is the following:

I use direnv to switch Ruby, so a typical .envrc reads something like use ruby 3.3.4. This works fine for projects, but sometimes, I have to run a single Ruby command using a specific Ruby. An example is the LSP server started by the VSCode Ruby LSP extension.

As of now, I use a similar approach as the original poster, but it doesn't work reliably. Another possibility would be activating the Ruby by setting the necessary env vars etc without direnv, but that's not DRY and cumbersome.

I've tried to source the file which defines use_ruby and then use that function, but since the direnv stdlib is not loaded, this fails as soon as a command like layout is hit.

There's direnv exec, but it requires a directory with a real .envrc somewhere up the road. Maybe a volatile ENVRC which doesn't use the "allow" safety mechanism:

ENVRC="use ruby 3.3.4" direnv exec "ruby --version"   # => ruby 3.3.4 (...)
ruby --version   # => ruby 2.6.10 (...)

Possibly a bad idea, but maybe you have a better one to tackle this?


Update, this is how I do it for now:

# Execute a command in the context of an installed Ruby.
#
# Usage: ruby-exec ruby command
ruby-exec() {
  if [ $# -ge 2 ]; then
    local ruby="$1"
    shift
    local command="$*"
    bash -c "
      eval $(direnv stdlib)
      source ~/.config/direnv/lib/ruby.sh
      use_ruby $ruby
      eval "$command"
    "
  else
    echo "Usage: ruby-exec ruby command"
  fi
}

The file ~/.config/direnv/lib/ruby.sh defines the use_ruby function which is called when something like use ruby is encountered in a .envrc.

This is very handy when you'd like to bootstrap e.g. a new Rails app as it solves the "hen egg problem" of having to switch to a specific Ruby before the directory is created.

svoop avatar Jul 09 '24 23:07 svoop