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

PowerShell support #124

Open
zimbatm opened this issue May 24, 2014 · 36 comments
Open

PowerShell support #124

zimbatm opened this issue May 24, 2014 · 36 comments

Comments

@zimbatm
Copy link
Member

@zimbatm zimbatm commented May 24, 2014

Alternatively to Cygwin, it should be possible to support the Microsoft PowerShell. The only unclear requirement that needs to be researched is if PowerShell would support evaluating code before each prompt.

  • Check how eval works and if there is a hook for executing direnv before each prompt
  • Install bash trough http://mingw.org/wiki/msys
  • Add a new shell_powershell.go that supports generating set instructions from the env diff.
@zimbatm zimbatm added this to the Cygwin support milestone May 24, 2014
@CMCDragonkai
Copy link
Contributor

@CMCDragonkai CMCDragonkai commented May 25, 2014

To support window's terminals, 3 types of scripts need to be executed:

  1. script.ps1
  2. script.bat
  3. script.cmd

Powershell runs .ps scripts, CMD should be used to run bat or cmd scripts. There are some minor differences between .bat and .cmd: http://stackoverflow.com/questions/148968/windows-batch-files-bat-vs-cmd (cmd is recommended script format now)

In order to set environment variables in CMD you need to use SET:

SET blah=blah
echo %cmd%

In order set environment variables in powershell (it uses a different syntax) see:

When using Cygwin, any environment variables set in Powershell or CMD are transferred to Cygwin child shell or vice versa.

So I can do this in Cygwin:

export EDITOR="nano"
CMD /C "echo %EDITOR%"

Which echos out nano.

@CMCDragonkai
Copy link
Contributor

@CMCDragonkai CMCDragonkai commented May 25, 2014

Which means you may need shell_powershell.go and shell_cmd.go. Most windows installations have powershell now, but older installations may only have CMD. I think XP and up?

@CMCDragonkai
Copy link
Contributor

@CMCDragonkai CMCDragonkai commented May 25, 2014

The starting area for PowerShell scripts is here:

$profile

As explained here: http://technet.microsoft.com/en-au/library/ee692764.aspx

However in order to run ps1 scripts, one has to activate their execution policy:

Here's my profile powershell:

Set-Location $env:USERPROFILE

CMD does not automatically look for any kind of profile script to run. People will need to hook in a script manually upon starting CMD: http://blog.cachemiss.com/articles/My%20cmd.exe%20Profile.pod

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented May 26, 2014

Interesting, thanks for all the material. CMD support is probably too legacy and require too much effort/hacks to work properly.

Apart from msys I also found an independent port of bash: http://win-bash.sourceforge.net/ Not sure what it's worth though.

Found this article on how to sign script: http://blogs.technet.com/b/heyscriptingguy/archive/2010/06/17/hey-scripting-guy-how-can-i-sign-windows-powershell-scripts-with-an-enterprise-windows-pki-part-2-of-2.aspx . According to http://technet.microsoft.com/en-us/magazine/2008.04.powershell.aspx?pr=blog I could also get a SSL cert for direnv.net and use it to sign the script.

@mdekstrand
Copy link

@mdekstrand mdekstrand commented Apr 20, 2016

For PowerShell, it looks like worst-case a custom Prompt function could look up the direnv stuff, and then repeat the default prompt behavior: https://technet.microsoft.com/en-us/library/hh847739.aspx

A quick search isn't revealing any other kind of hooking capabilities, but since the prompt is generated by running a function, that's a natural place to do it.

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Apr 20, 2016

Cool, thanks for looking that up. Are you planning on working on this further ? I would be keen on adding first-class windows support but don't have a development environment.

@mdekstrand
Copy link

@mdekstrand mdekstrand commented Apr 20, 2016

@zimbatm I'm not sure at present. For one thing, I do not know any Go. I have also been considering implementing DirEnv's core functionality directly in PowerShell.

I am very interested in having something like direnv in PowerShell, and am willing to do some work to get it. So far, have mostly just been trying to document what I know or learn while investigating whether it was already supported, to help whoever does eventually implement it.

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Apr 20, 2016

Alright that's cool too. The core logic is inside of cmd_export.go which is executed before every shell prompt. Basically it looks for the file and stores a diff inside of an environment variable. If you have a facility to keep a thread running inside of PowerShell you might not have to spawn a new process on each prompt and do that. Also bash is a requirement for direnv which might not fit very well with the windows environment.

@mdekstrand
Copy link

@mdekstrand mdekstrand commented Apr 21, 2016

If Bash is an internal requirement, it seems to me that it'd likely be better for direnv to focus on supporting Unix-like environments (Cygwin, MSYS, etc.) and for a separate project to enable similar functionality in native PowerShell.

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Apr 21, 2016

That's what's used to parse and execute the .envrc files. I wanted to keep the bash syntax and not re-invent a language. I bet it's possible to ship bash as a standalong executable alongside direnv in windows but yeah, something else might be preferable for PowerShell.

@staxmanade
Copy link

@staxmanade staxmanade commented May 25, 2016

Hey All,

I'd be interested in this on windows as well... Not sure if it helps, but wrote a custom cd command in PowerShell which give it some fun features. Maybe this could be used as an example on how to hook into the directory changing...

Code here: https://github.com/staxmanade/DevMachineSetup/blob/master/GlobalScripts/Change-Directory.ps1
Some blog posts describing the features here, here, and here

Also, not sure if I have time to work on it as I spend more time in Mac than windows - but if I jump on windows and run into some time I'll see what can be done.

@mcandre
Copy link

@mcandre mcandre commented Jun 11, 2016

+1

@petemounce
Copy link

@petemounce petemounce commented May 27, 2018

If this is still up for grabs, and no-one else is actively working on it... I know both powershell and enough golang to be dangerous, and would be prepared to test my own work on Windows 10 and Windows Server 2016. Would PRs on that basis be welcome? No promises on timeframe.

I'm not sure how to set things up to prevent them from rotting with regressions on further changes, however - I see travis CI is set up to produce releases, but I didn't see any configuration in it to run tests, and I noticed both various _test.go and what looks like an integration tests directory. Is there a contributing guide that someone could point me at?

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented May 27, 2018

Sounds good!

Is the Linux version of PowerShell close enough to be a realistic target for testing?

@petemounce
Copy link

@petemounce petemounce commented May 28, 2018

Not a clue, never used it. Will have to see :)

@petemounce
Copy link

@petemounce petemounce commented May 28, 2018

Would a dependency on Windows Subsystem for Linux be acceptable, to provide bash? I would think to look into that, first, as the easiest way to satisfy the dependency, if it also works of course.

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented May 28, 2018

yes if PowerShell for Linux can be installed under WSL then it's fine for development, most likely it will also be installable in Travis

@mcandre
Copy link

@mcandre mcandre commented May 30, 2018

Would a dependency on Windows Subsystem for Linux be acceptable

For now, sure! Note that some users configure Git Bash, Cygwin, MSYS, MinGW, and other environments, so testing against bash in these environments would also be helpful.

@klauern
Copy link

@klauern klauern commented Nov 25, 2018

If this is still up for grabs, and no-one else is actively working on it... I know both powershell and enough golang to be dangerous, and would be prepared to test my own work on Windows 10 and Windows Server 2016. Would PRs on that basis be welcome? No promises on timeframe.

Any progress made on this front? I know that with PowerShell Core, this might be an easier to approach problem on CI/CD environments, instead of having to spin up a separate Win10/Server 2016 instance.

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Nov 25, 2018

I wrote a quick version here: https://gist.github.com/ee97a194d77f162550b0347890eff120

It didn't require to extend direnv itself as PowerShell can read JSON. As you can see I decided to hook into the Global:prompt() since direnv is working better when evaluated before the prompt is displayed (instead of overriding cd).

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Feb 19, 2019

@zimbatm does direnv work natively in Powershell for you now? How did you solve the incorrect config directory issue, and how do you export variables in .envrc in the JSON case?

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Feb 19, 2019

@f0ff886f I don't use PowerShell day-to-day so that was more of a quick experiment, with the hope that somebody would pick this up and submit a PR

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Feb 19, 2019

OK, understood. I was under the impression this worked for someone :) I'm trying to get it going but its proving difficult to just get the basic functionality of the config file working. If I get somewhere I'll report back, its an awesome tool and would help me a lot.

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Feb 25, 2019

Just an update, I've followed the note here to configure DIRENV_CONFIG #442, and now at least the configuration errors are gone.

However with your script it still doesn't seem to do much, and I'm not sure even how to start debugging it.

direnv dump json shows me output of all my environment vars, but if I do a direnv export json I get:

/bin/bash: "C:/Users/Matt/scoop/apps/direnv/current/direnv.exe": No such file or directory
/bin/bash: source_env: command not found
{}�[31mdirenv: error exit status 127�[0m

Am I missing something in the PATH for it to find source_env? Also, is the proper format for .envrc always export FOO=bar regardless of the actual user shell? Or do we need to adapt the commands in .envrc to be shell-native (it is a bit confusing the connection between direnv, bash, and my shell, apologies!)

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Mar 4, 2019

@f0ff886f can you give me the output of direnv status?
It looks like direnv is not able to load the output from the stdlib, which is sourced by running eval "$(path/to/direnv stdlib)". If direnv is not able to find itself, the stdlib would not load.

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Mar 5, 2019

direnv exec path C:/Users/Matt/scoop/apps/direnv/current/direnv.exe
DIRENV_CONFIG c:\Users\Matt\AppData\Local\direnv
DIRENV_BASH C:\Windows\system32\bash.exe
Loaded RC path C:\swap\gitlab\tools\.envrc
Loaded RC allowed false
Loaded RC allowPath
Found RC path C:\swap\gitlab\tools\.envrc
Found watch: ".envrc" - 2019-02-25T12:34:12+01:00
Found watch: "..\\..\\..\\Users\\Matt\\AppData\\Local\\direnv\\allow\\187ad1d5f0f77018f4d1f15a99b0fef7593e2cf601c12de809aa0e3dd4b4fe1e" - 2019-02-25T12:35:16+01:00
Found RC allowed true
Found RC allowPath c:\Users\Matt\AppData\Local\direnv\allow\187ad1d5f0f77018f4d1f15a99b0fef7593e2cf601c12de809aa0e3dd4b4fe1e

I wonder if this could be a scoopism (its a package manager for Windows)

I'll try without scoop today

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Mar 6, 2019

I tried this without scoop packages (just put direnv.exe into my $env:PATH) with no change in behaviour: still get the source_env command not found.

What are the requirements for direnv, a bash executable on the PATH? Any special versions? I'm using ArchLinux WSL which seems to be providing the bash command.

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Mar 6, 2019

This might be a windows path formatting issue again. The direnv exec path has forward slashes but not the others.

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Apr 10, 2019

With direnv v2.20.0 it seems that there are no more errors with direnv with the source_env issue, but now I'm still wondering how should it work for Powershell (I've got things like DIRENV_DIFF set as an environment variable, but not my expected export FOO=foo). What is the expected format for .envrc content? bash commands? Or should I use Powershell commands for a Powershell environment?

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Apr 10, 2019

The .envrc format is always interpreted in bash. the direnv extracts the environment diff and re-exposes it to the target shell.

the project is not running on Azure Pipelines so if anyone is inclined to, it should be doable to add some Windows + PowerShell testing to the CI.

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Apr 10, 2019

Ok, so as the most basic test, if I do an export FOO=foo in the .envrc (and that's all), and then I make sure to direnv allow in the folder the .envrc is, it should function with the profile script you provided above, right?

Just trying to make sure I've got a simple and sane test :)

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Apr 10, 2019

yes and then when cd .. the FOO should be unset

@f0ff886f
Copy link

@f0ff886f f0ff886f commented Apr 10, 2019

Crap, it still doesn't work.

cat .envrc:

export FOO=foo

direnv status:

PS C:\work\tmp> direnv status
direnv exec path C:/Users/Matt/scoop/apps/direnv/current/direnv.exe
DIRENV_CONFIG c:\Users\Matt\AppData\Local\direnv
DIRENV_BASH C:\Windows\system32\bash.exe
Loaded RC path C:\work\tmp\.envrc
Loaded watch: ".envrc" - 2019-04-10T15:32:04+02:00
Loaded watch: "..\\..\\Users\\Matt\\AppData\\Local\\direnv\\allow\\76299ef9b7f4f2fd95dd2c551d84f8ab70c729dcbb71aaf4a7fcb5aad6d976cf" - 2019-04-10T10:23:38+02:00
Loaded RC allowed false
Loaded RC allowPath
Found RC path C:\work\tmp\.envrc
Found watch: ".envrc" - 2019-04-10T15:32:04+02:00
Found watch: "..\\..\\Users\\Matt\\AppData\\Local\\direnv\\allow\\76299ef9b7f4f2fd95dd2c551d84f8ab70c729dcbb71aaf4a7fcb5aad6d976cf" - 2019-04-10T10:23:38+02:00
Found RC allowed true
Found RC allowPath c:\Users\Matt\AppData\Local\direnv\allow\76299ef9b7f4f2fd95dd2c551d84f8ab70c729dcbb71aaf4a7fcb5aad6d976cf

when I cd into tmp, I do see the following env vars being set: DIRENV_DIFF, DIRENV_DIR, DIRENV_WATCHES, and when I cd out, the vars disappear.

One interesting thing I see is the value of DIRENV_DIR:

"DIRENV_DIR": "-C:\\work\\tmp",

note the hyphen before C:\\

Any ideas what I can try next?

@zimbatm
Copy link
Member Author

@zimbatm zimbatm commented Apr 12, 2019

One interesting thing I see is the value of DIRENV_DIR:

yes it's weird but expected :) The - prefix was added to avoid having the DIRENV_DIR being picked up by zsh's autocd feature.

What happens if you disable the direnv hook in your shell, go into the directory and run direnv export json ? Also check the exit status. I think bash is crashing somehow.

Other things to try:

  • run bash stdlib.sh in the direnv source root and see if it complains about anything.
  • edit rc.go line 135 and add set -x; in front of the argtmpl:
argtmpl := `set -x; eval "$("%s" stdlib)" >&2 && source_env "%s" >&2 && "%s" dump`
@xdhmoore
Copy link

@xdhmoore xdhmoore commented Aug 26, 2019

I attempted to further this thread. I didn't get very far but maybe this will help someone. I'm using WSL for bash, native windows powershell, and the amd64 windows direnv binary release for direnv. I got similar results with the direnv hook gist posted above.

  1. Without the direnv hook gist, running direnv export json gives:
PS 2019-08-25T21:22:30 D:\projects\cdk-workshop>direnv export json
/bin/bash: "D:/tools/bin/direnv.exe": No such file or directory
/bin/bash: source_env: command not found
{
  "DIRENV_DIFF": "eJw0ysuuc0AAAOB3mXUlNRS_pItph9K07gx_JFKXo2hRxYim735WZ_99QA_kz3cDWiB_ANYdxQgSrDtABgyW47gfurrIxnccZ3nD0G5o3veuB5s_SpB31BQXyKA4L--1Vs0FI_uQH8UJiXp-p2IW5ZHZH7qXVfqUqyrszKQhW-jqlbhllfIy4207JL4ukrqaOru8cY3BqAT5QvtaYeiv3BOnFZEEQoXRwd6T3alLaPAajEbtNvlc8eNCNliCiNldZvFApFpS3UdwwtbkRT29QqjdSic7M_-DCo1OxoelEbGihLsxNUwO24LeNjk0G9sfcFOk9voPWt1QMJ6SscJ15B8pKbzaQqWhTFGyTKdZMsOWIoSsJEF0Z_Jovwff728AAAD__3dbbIY=",
  "DIRENV_DIR": "-D:\\projects\\cdk-workshop",
  "DIRENV_WATCHES": "eJxszjFOxDAQBdC7uA7Idhw7cYdYOpBoqPgUw3iiDRvWkW02SIi701EgLvD0nr_UI7WjiuoQga3kN-FWAU6nqz2XUz3mDbiW86Ww6tRDTm15FxXN4H2YtHauU3efS21VxVY-5Lv7BW8j8FSlVGDPuTYpwM22HagRcJ-ZViAtRc4XgNY178DotbNO3DQ6Inkd2OkQUrDkebQz92Pore-TEc16Mt4lbWeTjPAgNEuY_xuGv8OXnwAAAP__Aw5O4A=="
}direnv: error exit status 127

I guess the problem is related to the direnv path needing to be translated to/mnt/d/tools/bin/direnv.exe so that it's reachable from inside WSL/bash. However, would this even work? It would be essentially trying to run the windows direnv binary in an ubuntu container...

  1. running `bash "stdlib.sh" from the direnv source directory yields
PS 2019-08-25T21:24:38 D:\projects\direnv>bash ./stdlib.sh
: invalid optione 11: set: -
set: usage: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
./stdlib.sh: line 12: $'\r': command not found
./stdlib.sh: line 15: $'\r': command not found
./stdlib.sh: line 18: $'\r': command not found
./stdlib.sh: line 23: $'\r': command not found
./stdlib.sh: line 30: $'\r': command not found
./stdlib.sh: line 31: syntax error near unexpected token `$'{\r''
'/stdlib.sh: line 31: `direnv_layout_dir() {

but that seems like I'm doing something wrong.
3) I attempted to make the suggested change to rc.go and build it on WSL, but I was unsuccessful in building either in WSL (built but wouldn't run in Windows. maybe there's a way, I just didn't see it.) or using MinGW on windows (couldn't get building).

Two thoughts:
Maybe it would help if it could build on windows (outside of WSL, cygwin, msys, etc).

While there are a variety of bash environments on windows, (cygwin, msys, git-bash, wsl), would it make things simpler to avoid use of bash entirely? bash in windows is somewhat heterogeneous and hefty, and calling out to it on every powershell prompt doesn't sound ideal. Also, I'm guessing supporting cygwin path translation vs msys path translation vs WSL path translation could be a headache, but I'm just guessing. Maybe only one flavor of windows bash could be supported, or even better, perhaps the .envrc syntax for powershell could be limited something more like a .properties file syntax:

FOO=bar
BAZ=bwop

It's not ideal, but then one wouldn't have to deal with the bash-on-windows weirdness at all. Also, perhaps it would be more realistic to implement than powershell syntax.

But perhaps I've made some false assumptions without reading the code. Anyway, thanks for building direnv. I use it all the time on my mac. It's super great combined with venv.

@mcartoixa
Copy link

@mcartoixa mcartoixa commented Apr 18, 2021

FYI maybe you could talk to this guy? https://github.com/takekazuomi/posh-direnv 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants