Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support per-window variable environments #15452

Closed
lloeki opened this issue Nov 14, 2016 · 22 comments
Closed

Support per-window variable environments #15452

lloeki opened this issue Nov 14, 2016 · 22 comments
Assignees
Labels
bug Issue identified by VS Code Team member as probable bug linux Issues with VS Code on Linux macos Issues with VS Code on MAC/OS X workbench-os-integration Native OS integration issues
Milestone

Comments

@lloeki
Copy link
Contributor

lloeki commented Nov 14, 2016

Problem

Various tools don't operate correctly depending on the order and the manner with which VSCode is started on macOS.

Also, persisted state is not restored consistently.

Note: the problem is similar to atom/atom#4126. Although I feel dirty pointing you to a thread pertaining to That Other Editor, the issue is largely the same and some discussion happened over there that one may want to look into for the full effect.

Cause

Depending the manner in which VSCode is started, a different environment is inherited.

  • launchd event: inherits launchd mostly blank env, which would mean no shell env vars save from some magic happening and my env vars from a login shell are set (good!)
  • code in the terminal: inherits currently set vars

This applied to when the app is started, not when a new window is opened, in which case that window will inherit the current process env (which is normal OS X behaviour).

Current workaround / Anti-feature

Manually control Code startup each time you want to use it in a specific environment.

Why is it an anti feature? If you want two projects open at the same time but with different environments, you're busted.

Also, long running sessions and "wait what env was that started with already?" (session can also mean the idiomatic "document != app" macOS way: "Visual Studio Code.app is started but no windows are opened").

Also also, frustration quickly sets in when you start it up the wrong way and have to quit and restart halfway through your work and notice your linter does not actually run (manual config does not cut it because 1. it's manual and 2. constantly changing versions means constantly changing path).

Possible solution

  1. sanitize environment upon every launch, with local environment management is bestowed to package implementor (meaning detection of .git, Gemfile, .rubocop.yml, .gopath, which they have to do anyway else at least starting via launchd is broken, if not more), not to manual handling by developer.
  2. have a clean environment per window (which means per process apparently), which is what Atom chose to do but this approach is fraught with peril.

Consequences

  • PATH & al. is properly set and tools like linters can leverage the env to use chruby/rbenv/whatever.
  • Clicking the icon, starting via spotlight, opening a file from Finder, using open -a "Visual Studio Code" and using code foo on the terminal are all consistent, whatever the order they are executed in.
  • Everything is now consistent and we can now rejoice as glittery roses spontaneously bloom out of Bose-Einstein condensates.

Additional note

On another planet, I don't know if this issue applies to other OSes as well besides macOS. Everything depends on how process management and app/doc/task GUI model is expected to be handled there.

Final word

All of this really matters daily when you juggle between projects and makes VSCode feel like a brittle product, making angry coworkers throwing rusted nails at me for having pushed VSCode on them. (I realise I pushed the same argument forward on the Atom issue, but hey, we all know deep inside that VSCode is OvbiouslyBetter™, and being thrown sharp objects at twice is doubleplus unfun).

Details

  • VSCode Version: Code 1.7.1 (02611b4, 2016-11-03T13:46:00.226Z)
  • OS Version: Darwin x64 16.1.0
  • Extensions:
Extension Author Version
Go lukehoban 0.6.49
Ruby rebornix 0.10.1
slim sianglim 0.0.1

Steps to Reproduce:

  1. open VSCode from Dock/Spotlight
  2. toggle developer tools and look at process.env in JS console
  3. open terminal
  4. export FOO=bar
  5. run code somewhere or whatever
  6. toggle developer tools in new window and look at process.env in console, notice there's no FOO
  7. quit VSCode completely (for real)
  8. run code somewhere or whatever
  9. toggle developer tools in new window and look at process.env in console, notice there's FOO
  10. open new code window
  11. toggle developer tools in new window and look at process.env in console, notice there's FOO
  12. open new terminal tab (that will not have FOO)
  13. run code somewhereelse or whatever
  14. toggle developer tools in new window and look at process.env in console, notice there's FOO
@joaomoreno
Copy link
Member

Since I can't reproduce the problems you raise in steps 6 and 12, I'll close this issue. Please see my screencast recorded just now on the latest Insiders build:

https://www.youtube.com/watch?v=3WvA-mK6xu0

I believe you can reproduce it on your machine, though, so let's try to find out why that happens. What do you get when running which code?

PS: I found it tough to understand what your problem is, given the verbosity of your prose. Thanks for the Steps to Reproduce section, it would've been hard otherwise. When filing future issues, please try to keep it short and simple.

PPS: You forgot to rename Atom to VS Code in one instance, during your copy paste.

@lloeki
Copy link
Contributor Author

lloeki commented Nov 14, 2016

Here's a screencast reproducing the issue. Notice that there are three separate runs of VS Code, between which I entirely quit the application:

  • the first one is started from the terminal before the env var is set
  • the second one is started from the terminal after the env var is set
  • the third one is started from launchd via Spotlight

In each of those runs, I open the foo dir, the bar dir, and a new window. Notice that in the second run, every window gets the FOO env var.

Please note that when I say "all is fine" for the first run, obviously this is WRT the FOO var, as other vars are obviously possibly leaking (just as on the second run), we're just not scrutinizing them.

Here's the output you asked for:

vscode_15452> which code
/usr/local/bin/code
vscode_15452> ls -l $(which code)
lrwxr-xr-x  1 lloeki  wheel  68 12 May  2016 /usr/local/bin/code -> /Applications/Visual Studio Code.app/Contents/Resources/app/bin/code

PS: sorry for the verbosity. I'll keep things short in the future.

PPS: nice catch, well played ;-)

@joaomoreno
Copy link
Member

To fix the environment of the second window in your second run, we could have every window created from the UI have a clean environment too, instead of inheriting the one from spawn time. But then, we'd just have other users complaining that this wasn't expected behaviour and that they expect the initial environment to propagate to all windows.

There are different ways to approach this problem. This is the set of rules we've decided to go with:

  • When spawned from Spotlight, Code will spawn a shell for the single purpose of getting the same environment the user would get, when running it from a shell.
  • When spawned from the command line, Code will simply inherit the shell's environment.
  • New windows, created from Code itself, will inherit the initial environment that Code had at spawn time.
  • New windows created from the command line will inherit the environment currently from that command line session.

We believe this set of rules makes most users happy and not weary of unexpected behaviour.

@lloeki
Copy link
Contributor Author

lloeki commented Nov 15, 2016

  • New windows created from the command line will inherit the environment currently from that command line session

Untrue, or at least ambiguous. The following is currently correct:

  • New windows created from the command line will inherit the environment that Code had at spawn time, merged with the one currently from that command line session.

screen shot 2016-11-15 at 09 37 20

  • New windows , created from Code itself, will inherit the initial environment that Code had at spawn time.

This is IMHO the pain point: to me only the window that pertains to the path passed to code should be imbued with the environment, whether it's the first one or not.

To fix the environment of the second window in your second run, we could have every window created from the UI have a clean environment too, instead of inheriting the one from spawn time. But then, we'd just have other users complaining that this wasn't expected behaviour and that they expect the initial environment to propagate to all windows.

So there are two opposing use cases here. Could it be made into a setting? That'd be awesome as I'd love to have control over this so that code whatevs would always do the same thing without having to remember whether (or how) the app has been started or not.

Also, there are a couple corner cases. What's the behaviour you expect to have upon:

  • updates that restart Code?
  • OS reboots that restart Code ("window.reopenFolders": "all" and restored session windows)?

AFAICT both may make the user lose its env if it was spawned from the command line.

@joaomoreno
Copy link
Member

Yes, that disambiguation was necessary. 👍

Don't you think it would be wrong, or at the very least confusing, to spawn Code with FOO=bar code, thus opening window A; and then open window B from within Code and not have FOO set in there?

None of the two corner cases will preserve the environment.

@lloeki
Copy link
Contributor Author

lloeki commented Nov 15, 2016

Not confusing at all for me, as this does what I expect from a multiwindow document-based app on macOS:

  • when the app is started it either starts afresh and presents a new document (which are two distinct steps), or starts and restores previous state (depending on system and/or app settings)
  • when BAR=42 code foo is run it starts the app, and then opens the foo "document" (that is, a workspace in Code that points to the foo directory), so the environment is tied to the workspace
  • when BAR=42 code is run, it starts the app, and then opens a blank "document" (that is, a workspace in Code), so, again, the environment is tied to the blank workspace

This becomes increasingly important as you start to develop within different Go workspaces, across varying tech stacks, and using various env vars that are tied to each project (for, say, Docker, rake, or rbenv) that you don't want to leak from one repo/project/workspace to another.

This behaviour integrates naturally with the platform conventions as well as making it easy to support OS features such as proper state restoration (possibly serializing the env to be restored upon restart/after update?). This is tangential to this issue but I'd love to be able to hit "yes, restart and update right now!" on a new release notification and have things continue to work, as well as the editor surviving logouts/reboots, but that depends the extend of which you want to push blending with the platform expectations.

A quick informal poll shows that coworkers around me that use macOS seem to generally agree with this behaviour. As a general rule, the ones that "get" the behaviour you expect come from a Linux background yet accept it as a glitch they have to work around. As a rule of thumb people over here generally prefer having a warning that GOPATH isn't set than dependencies installing into the wrong GOPATH because Code was started in such a way previously.

@joaomoreno
Copy link
Member

You've at least convinced me to seriously consider making a change. Good job! 👍

@joaomoreno joaomoreno reopened this Nov 16, 2016
@joaomoreno joaomoreno added this to the November 2016 milestone Nov 16, 2016
@joaomoreno joaomoreno added the bug Issue identified by VS Code Team member as probable bug label Nov 16, 2016
@lloeki
Copy link
Contributor Author

lloeki commented Nov 16, 2016

Awesome! Thanks to you for having kept on lending an ear :-)

@pelted
Copy link

pelted commented Jan 24, 2018

Running into issue that may be related. Custom Task to run rails test does not run in the correct environment context with the rbenv shimmed version of Ruby or other ENV variables.

Code's terminal windows open with the correct context, but not tasks. Is there a way around this?

@lloeki
Copy link
Contributor Author

lloeki commented Jan 24, 2018

@pelted Interesting, I'll take that into account when I'm diving into the code (which happens with great irregularity but this issue is still on my radar!)

@szhu
Copy link

szhu commented Apr 20, 2018

For those who are still waiting for a workaround, I made a script that wraps around code that can help:
https://github.com/szhu/important-things/blob/master/bin/code

This script makes sure that opening a folder using code behaves exactly the same as opening it through the GUI. This behavior is guaranteed and not hacky, because the way the script works is it launches VSCode through the GUI first.

Place this script somewhere such that it has higher PATH precedence than /usr/local/bin/code. (I have ~/.local/bin occurring early in my path so I put it there.)


Btw: If you don't need code to work in pipes, a short solution would be to do this:

#!/bin/bash

open -b com.microsoft.VSCode "$@"

But then you don't get 100% feature parity with code.

@joaomoreno joaomoreno added macos Issues with VS Code on MAC/OS X linux Issues with VS Code on Linux and removed macos Issues with VS Code on MAC/OS X info-needed Issue requires more information from poster labels Aug 22, 2018
@joaomoreno joaomoreno changed the title Inconsistent environment and behaviour on macOS Support per-window variable environments Aug 22, 2018
@alexwhittemore
Copy link

alexwhittemore commented Aug 22, 2018

FWIW @joaomoreno @Tyriar this is ultimately what I'm getting at with #56125 - PATH specifically changing is of course a problem for me, but I hadn't even realized the extent of my "problem," w.r.t. environments getting inherited on subsequent launches.

For instance,
(terminal 1)

$ workon my_env_1
(my_env_1) $ code .

(terminal 2)

$ workon my_env_2
(my_env_2) $ code .

not only results in two Code windows with non-useful PATHs, but also a weird chimera environment in the second window with env variables from both my_env_2 and my_env_1, which isn't something I'd even realized before.

@joaomoreno
Copy link
Member

@alexwhittemore So... what's your expected behavior?

@alexwhittemore
Copy link

As a simple test, open two terminals:

in term 1:

Alexs-MBP-2018:~/Desktop/testdir1 
› workon test_env1
(test_env1) Alexs-MBP-2018:~/Desktop/testdir1 
› export TESTVAR="ENV1"
(test_env1) Alexs-MBP-2018:~/Desktop/testdir1 
› export UNIQUE="ENV1"
(test_env1) Alexs-MBP-2018:~/Desktop/testdir1 
› code .

In a Code terminal we see

Alexs-MBP-2018:~/Desktop/testdir1
› echo $VIRTUAL_ENV
/Users/alexw/.virtualenvs/test_env1
Alexs-MBP-2018:~/Desktop/testdir1
› echo $TESTVAR
ENV1
Alexs-MBP-2018:~/Desktop/testdir1
› echo $UNIQUE
ENV1

of course.

Moving over to a second terminal:

Alexs-MBP-2018:~/Desktop/testdir2 
› workon test_env2
(test_env2) Alexs-MBP-2018:~/Desktop/testdir2 
› export TESTVAR="ENV2"
(test_env2) Alexs-MBP-2018:~/Desktop/testdir2 
› export TESTVAR="ENV2"
(test_env2) Alexs-MBP-2018:~/Desktop/testdir2 
› code .

And in Code:

Alexs-MBP-2018:~/Desktop/testdir2
› echo $VIRTUAL_ENV
/Users/alexw/.virtualenvs/test_env2
Alexs-MBP-2018:~/Desktop/testdir2
› echo $TESTVAR
ENV2
Alexs-MBP-2018:~/Desktop/testdir2
› echo $UNIQUE
ENV1

In this second case, TESTVAR and VIRTUAL_ENV are correct, but I'd expect UNIQUE to be unset. This can lead to oddities where launching subsequent windows results in having partial environments from previous windows.

In my use case, the hangup is, if I launch Code inside a virtualenv, subsequent windows not-necessarily-launched-from-a-virtualenv will adopt that virtualenv. And anyway, the behavior is inconsistent depending on order-of-window-launched, which seems undesirable per se.

@segevfiner
Copy link
Contributor

Note #55194 which fixes one of the issues with this. But there may be more. VS Code seems to already have the basic infrastructure for this in-place, I think it's just a matter of fixing cases where it's not working, and ironing out it's behavior.

@alexwhittemore
Copy link

Thanks for the info!

@joaomoreno
Copy link
Member

@lloeki We started working on this and coming up with a better strategy over here: #108804 (comment)

I believe today some of the inconsistencies you mention are already fixed. Namely step (6) on the initial steps is no longer true: it works today.

Will close this issue and move the work over to #108804

@github-actions github-actions bot locked and limited conversation to collaborators Jan 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue identified by VS Code Team member as probable bug linux Issues with VS Code on Linux macos Issues with VS Code on MAC/OS X workbench-os-integration Native OS integration issues
Projects
None yet
Development

No branches or pull requests

7 participants