purcell/envrc

project-compile not applying env when switching projects

TxGVNN opened this issue · 8 comments

Hello,

I am currently experiencing an issue with project-compile. I usually switch to a project by call project-compile directly.
This is my configuration:

(require 'envrc)
(setq envrc-debug t)
(envrc-global-mode)

em -Q --load config.el

When I call M-x project-compile and select another project that has a .envrc file, the environment does not get applied.

I have tried to debug the issue, but was unable to identify the root cause.

Thank you.

Hmmm, that case is actually tricky to address: there's no buffer in the destination ("other") project in which envrc-mode could be activated before the process is started.

You can work around it by doing this:

(defun my/ensure-current-project (fn &rest args)
  (let ((default-directory (project-root (project-current t))))
    (with-temp-buffer
      (envrc-mode 1)
      (apply fn args))))

(advice-add 'project-compile :around #'my/ensure-current-project)

for now, but I'll have a think about how to address this more thoroughly.

One tricky thing here is that users might not have envrc-mode enabled in every buffer — it's technically possible to decide to enable it only in certain modes or projects. But the above solution assumes that if envrc-mode is enabled in the calling project, you would want it enabled in the destination/other project — that's not really a valid assumption in all cases, even if most users would just enable envrc-global-mode.

Note also that project-async-shell-command and project-shell-command are probably also broken in the same way: you could add further advice-add lines for them, as above.

It works. Thank you very much.

Hmmm, that case is actually tricky to address: there's no buffer in the destination ("other") project in which envrc-mode could be activated before the process is started.

But a question, I check *envrc-debug* and see the env is loaded, why do we still need trick with new temp buffer?

Yes, I think you're saying that envrc-mode is active in the resulting compilation buffer, and that's true, but it looks like compile actually has some code which propagates the calling buffer's local environment to the compilation buffer and wipes out the changes applied there by envrc!

The sequence in compile is this:

  • The caller's local env and path are noted
  • A compilation buffer is created
  • The compilation mode is initialised in that buffer, which causes envrc-mode to read and apply the local env for that directory
  • compile copies the caller's local env and path into the buffer
  • The compilation process is started

So it's all a bit unfortunate, because the compile author was trying to do the right thing, but ends up subverting it for your use case. In fact, if you followed the rule that when you call a process-starting command, you always want to use the caller's environment, we could say this is the correct behaviour. However, project-compile and friends have different (somewhat unusual) semantics, hence the mismatch.

Thank you for taking time to explain to me. I understood more.

Me too — until you asked, I didn't actually realise that envrc-mode was enabled in the resulting buffer, so figuring out what was happening was useful to me.